Rails在多个实例/服务器上重新加载动态路由 [英] Rails reload dynamic routes on multiple instances/servers

查看:69
本文介绍了Rails在多个实例/服务器上重新加载动态路由的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们如何强制Rails在多个服务器/实例上重载路由?

How can we force Rails to reload_routes on multiple servers/instances?

我们在Google App-Engine中有一个多租户平台,可在5个以上的实例上运行,我们希望所有站点都从后端定义自己的一组路由。每当我们有一个新站点时,我们当前都必须重新启动所有服务器才能访问新路由。

We have a multi-tenant platform in Google App-Engine running on 5+ instances and we want all of our sites to define their own set of routes from the backend. Whenever we have a new site we currently have to restart all servers in order to be able to access the new routes.

我们遵循了指南,但是它仅在本地环境下有效,并且在不重启服务器的情况下不会更新生产中的所有所有服务器上的路由。

We followed this guide but it does only work on a local environment and is not updating routes on all servers in production without restarting the servers.

我们的路线文件如下:

routes.rb

routes.rb

Frontend::Application.routes.draw do
  root 'home#index'
  ...
  DynamicRoutes.load
end

lib / dynamic_routes.rb

lib/dynamic_routes.rb

def self.load 
  Frontend::Application.routes.draw do
    Site.all.each do |site|
      site.routes.each do |custom_route|
       route_name = custom_route[0]
       route = custom_route[1]

       # write the route with the host constraint
       self.constraints(:host => site.hostname) do
         case route_name
         when :contact_form
           mapper.match "#{route}", to: 'contact_forms#new' as: "contact_#{site.id}"
         end
         ...
       end
     end
    end
  end
end

def self.reload
  Frontend::Application.reload_routes!     
end

每次更新路线或创建新站点后,我们正在运行 DynamicRoutes :: reload

after each update of routes or creation of a new site we are running DynamicRoutes::reload

推荐答案

我们终于找到了一个效果很好的解决方案,也不会太大地影响性能。我们使用这样的事实,即生产中的线程在请求​​之间保持状态。因此,我们决定创建一个中间件,以检查路由更改的最新时间戳,并在时间戳与 Thread.current 中保存的时间戳不同的情况下,强制使用 Frontend :: Application.reload_routes!

We finally found a solution that works pretty well and is also not affecting performance too much. We use the fact that Threads in production are keeping states across requests. So we decided to create a middleware that checks the latest timestamp of a routes change and in case the timestamp is not the same as the one saved in Thread.current we force a Frontend::Application.reload_routes!

config / production.rb

config/production.rb

Frontend::Application.configure do
  ...
  config.middleware.use RoutesReloader
  ...
end

app / middleware / routes_reloader.rb

app/middleware/routes_reloader.rb

class RoutesReloader
  SKIPPED_PATHS = ['/assets/', '/admin/']

  def initialize(app)
    @app = app
  end

  def call(env)
    if reload_required?(env)
      timestamp = Rails.cache.read(:routes_changed_timestamp)

      if Thread.current[:routes_changed_timestamp] != timestamp
        Frontend::Application.reload_routes!

        Thread.current[:routes_changed_timestamp] = timestamp
      end
    end

    @app.call(env)
  end

  private

  def reload_required?(env)
    SKIPPED_PATHS.none? { |word| env['PATH_INFO'].include?(word) }
  end
end

app / model / routes.rb

app/model/routes.rb

class Routes < ActiveRecord::Base

  after_save :save_timestamp

  private

  def save_timestamp
    ts = Time.zone.now.to_i
    Rails.cache.write(:routes_changed_timestamp, ts, expires_in: 30.minutes)
  end
end

优点:


  • 您可以在某些路径(例如/ assets /和/ admin /

  • 线程处理多个请求,并且重新加载仅发生一次

  • 您可以在任意喜欢的模型上实现

注意事项:


  • 新线程将两次加载路由

  • 如果您清除Rails Cache,所有线程都将重新加载路由(您可以使用持久性解决方案来解决;例如,将时间戳保存到mysql中,然后保存到缓存中)
  • >
  • New Threads will load routes twice
  • All Threads will reload routes if you clear Rails Cache (you could overcome this with a persistent solution; e.g. saving the timestamp into mysql and then into cache)

但是总体而言,我们没有发现任何性能下降。

But overall we didn't recognise any performance drops.

我们一直在努力现在有了这个多年上述解决方案是第一个真正帮助我们在多个线程上重新加载路由的解决方案。

We have been struggling with this now for years and the above solution is the first that really helped us reloading routes on multiple threads.

这篇关于Rails在多个实例/服务器上重新加载动态路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆