机架中间件和线程安全

Mic*_*ich 7 ruby rack ruby-on-rails thread-safety puma

我有一个我的Rails 4应用程序使用的自定义机架中间件.如果客户端没有提供有效信息(我正在使用API​​),中间件本身就是默认AcceptContent-Type标题application/json.因此,在每个请求之前,它会更改这些标头,并在每次请求之后添加一个自定义X-Something-Media-Type头,并带有自定义媒体类型信息.

我想切换到Puma,因此我有点担心这种中间件的线程安全性.我没有使用实例变量,除了一次@app.call我们在每个中间件中遇到的常见变量,但即使在这里我也复制了我在RailsCasts的评论中读到的内容:

def initialize(app)
 @app = app
end

def call(env)
 dup._call(env)
end

def _call(env)
 ...
 status, headers, response = @app.call(env)
 ...
Run Code Online (Sandbox Code Playgroud)

dup._call为了处理线程安全问题真的有用吗?

除了@app实例变量之外,我只使用当前env变量构建的当前请求:

request      = Rack::Request.new(env)
Run Code Online (Sandbox Code Playgroud)

我打电话env.update来更新标题和表单信息.

当我将切换Webrick到并发Web服务器时,如果期望中间件出现问题,这是否足够危险Puma

如果是的话,您是否知道一些方法可以进行一些测试以隔离我的中间件中非线程安全的部分?

谢谢.

小智 5

是的,dup中间件必须是线程安全的。这样,您从中设置的任何实例变量_call都将在被欺骗的实例上设置,而不是在原始实例上设置。您会注意到,围绕Rack构建的Web框架以这种方式工作:

进行单元测试的一种方法是断言_call在重复实例上调用了该实例,而不是原始实例。

  • 作为推论,如果您不设置/更新实例变量,则没有必要在中间件上调用 `dup`。或者,为共享缓存使用线程安全的数据结构,例如并发 ruby​​ 的缓存映射。 (2认同)