【问题标题】:Rails 5 halt a custom http middleware while reloader is reloading.Rails 5 在重新加载时停止自定义 http 中间件。
【发布时间】:2018-06-26 22:16:12
【问题描述】:

在 Rails 5 开发模式下,我在自定义会话中间件中不断收到此 Net::ReadTimeout(Net::ReadTimeout) 错误,该中间件向我的本地模拟自定义会话引擎发出 http 请求。此外,该错误仅在我进行代码更改并且 Rails 呈现错误页面后触发。这非常烦人,并且确实减慢了开发过程,因为我们都必须刷新两次才能看到代码更改的结果。

跟踪这些中间件中的代码后,我的自定义会话中间件似乎在重新加载器完成重新加载之前启动了 http 请求。

我想知道我们是否可以停止/停止机架中间件请求,直到重新加载完成为止。

Rails 版本:5.1

Ruby 版本:2.4.1

我在重新加载器完成重新加载之前和之后放置了以下日志消息

应用程序.rb

ActiveSupport::Reloader.to_run do
  puts 'Reloading'
end

ActiveSupport::Reloader.to_complete do
  puts 'DONE Reloading'
end

custom_session_siddleware.rb

def call(env)
  ...
  puts 'Session Processing'
  http = Net::HTTP.new(uri, port)
  ...
  @app.call(env)
end

我更改代码并刷新后的输出

Reloading
Session Processing
DONE Reloading

这是我所有的中间件

use Rack::Sendfile
use ActionDispatch::Static
use ActionDispatch::Executor
use ActiveSupport::Cache::Strategy::LocalCache::Middleware
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use RequestStore::Middleware
use ActionDispatch::RemoteIp
use ActionDispatch::ShowExceptions
use ActionDispatch::DebugExceptions
use ActionDispatch::Reloader
use ActionDispatch::Callbacks
use ActiveRecord::Migration::CheckPending
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use Rack::Head
use Rack::ConditionalGet
use Rack::ETag
use MyCustomSession::CustomSessionMiddleware

【问题讨论】:

  • uri 是否指向正在运行的应用程序?
  • 您的输出显示了所有三个步骤的发生......这与超时异常有什么关系?
  • 所以我们有一个模拟自定义会话服务的引擎,它只为开发而安装,所以 CustomSessionMiddleware 将在开发模式下模拟并在生产模式下命中真实服务
  • 输出显示代码更改时的事件顺序。 1. 重新加载器卸载所有类,2,我的自定义会话中间件调用是一个 http 请求(它超时),3. 重新加载器完成重新加载。
  • 我的理论是这样。发生超时是因为自定义会话中间件正在调用处于卸载或重新加载中间的路由。并且事件的顺序应该是 1. 重新加载。 2、DONE Reloading 3、会话处理。我不确定为什么重新加载中间件会在重新加载完成之前让请求继续向下机架中间件。

标签: ruby-on-rails ruby-on-rails-5


【解决方案1】:

如果您的自定义中间件正在向正在运行的 Rack 应用程序发出请求,那么您很容易遇到麻烦。但它可以工作。


当您的初始请求在 Reloader 中时,实际的重新加载已经发生——但这只是 卸载

卸载后,任何应用程序(或引擎)类都需要在下次访问时再次自动加载...我认为这就是您遇到问题的地方:内部请求需要加载一些东西,但在外部请求处于活动状态时不能这样做。

要解决此问题,外部请求需要通知系统它处于安全位置,以便另一个线程/请求加载新代码。具体来说,您需要用permit_concurrent_loads 包装Net::HTTP 请求(仅- 不是 @app.call(env))。

【讨论】:

  • 文档相当混乱,我尝试在调用方法中用ActiveSupport::Dependencies.interlock.permit_concurrent_loads do 包装@app.call(env) 之上的所有内容。
  • 或者我必须用Concurrent::Future.execute do之类的东西包装那个http请求??
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-03
  • 1970-01-01
  • 2020-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多