Ruby on rails Rails在多个实例/服务器上重新加载动态路由
我们如何强制Rails在多个服务器/实例上重新加载路由 我们在Google App Engine中有一个多租户平台,在5+个实例上运行,我们希望我们的所有站点都能从后端定义自己的路由集。每当我们有一个新的网站,我们目前必须重新启动所有服务器,以便能够访问新的路由 我们遵循了这一点,但它只在本地环境下工作,并且在不重新启动服务器的情况下,不会更新生产中所有服务器上的路由 我们的路由文件如下所示: routes.rbRuby on rails Rails在多个实例/服务器上重新加载动态路由,ruby-on-rails,ruby,ruby-on-rails-3,ruby-on-rails-4,routing,Ruby On Rails,Ruby,Ruby On Rails 3,Ruby On Rails 4,Routing,我们如何强制Rails在多个服务器/实例上重新加载路由 我们在Google App Engine中有一个多租户平台,在5+个实例上运行,我们希望我们的所有站点都能从后端定义自己的路由集。每当我们有一个新的网站,我们目前必须重新启动所有服务器,以便能够访问新的路由 我们遵循了这一点,但它只在本地环境下工作,并且在不重新启动服务器的情况下,不会更新生产中所有服务器上的路由 我们的路由文件如下所示: routes.rb Frontend::Application.routes.draw do ro
Frontend::Application.routes.draw do
root 'home#index'
...
DynamicRoutes.load
end
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
假设您没有共享存储:您可以编写一个操作,为该特定实例重新加载路由。当您触发DynamicRoutes::reload时,您将请求其他实例的重新加载操作
如果您确实有共享存储,请编写一个before_操作,每当“触碰”特定文件时重新加载路由,如果您希望所有实例都重新加载路由,请触碰该文件。我们最终找到了一个效果非常好且对性能影响不大的解决方案。我们利用生产中的线程在请求之间保持状态这一事实。因此,我们决定创建一个中间件,用于检查路由更改的最新时间戳,以防时间戳与保存在
线程中的时间戳不同。当前我们强制执行前端::Application.reload_routes代码>
config/production.rb
Frontend::Application.configure do
...
config.middleware.use RoutesReloader
...
end
app/middleware/routes\u 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
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缓存,所有线程都将重新加载路由(您可以通过持久性解决方案解决这个问题;例如,将时间戳保存到mysql中,然后保存到缓存中)
但总体而言,我们没有发现任何业绩下降
多年来,我们一直在努力解决这个问题,上面的解决方案是第一个真正帮助我们在多个线程上重新加载路由的解决方案。在保存站点模型的回调后,您是否尝试将DynamicRoutes::reload
添加到中?是的,我已经尝试过了。此外,多次保存站点和路由也无法保护到的路由reload@Mik使用Frontend::Application.routes\u reloader.reload代码>重新加载的方法routes@VishalJAINFrontend::Application.reload_路由
是该方法的别名