9

I have a custom rack middleware used by my Rails 4 application. The middleware itself is just here to default Accept and Content-Type headers to application/json if the client did not provide a valid information (I'm working on an API). So before each request it changes those headers and after each request it adds a custom X-Something-Media-Type head with a custom media type information.

I would like to switch to Puma, therefore I'm a bit worried about the thread-safety of such a middleware. I did not play with instances variables, except once for the common @app.call that we encounter in every middleware, but even here I reproduced something I've read in RailsCasts' comments :

def initialize(app)
 @app = app
end

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

def _call(env)
 ...
 status, headers, response = @app.call(env)
 ...

Is the dup._call really useful in order to handle thread-safety problems ?

Except that @app instance variable I only play with the current request built with the current env variable :

request      = Rack::Request.new(env)

And I call env.update to update headers and forms informations.

Is it dangerous enough to expect some issues with that middleware when I'll switch from Webrick to a concurrent web server such as Puma ?

If yes, do you know a handful way to make some tests en isolate portions of my middleware which are non-thread-safe ?

Thanks.

Mich
  • 729
  • 1
  • 7
  • 14

1 Answers1

6

Yes, it's necessary to dup the middleware to be thread-safe. That way, anything instance variables you set from _call will be set on the duped instance, not the original. You'll notice that web frameworks that are built around Rack work this way:

One way to unit test this is to assert that _call is called on a duped instance rather than the original.

bryanp
  • 427
  • 3
  • 9
  • 2
    As a corollary, iff you don't set/update instance variables it's not necessary to call `dup` on the middleware. Alternatively, use thread-safe data structures e.g. concurrent-ruby's cache map, for a shared cache. – ioquatix Dec 04 '15 at 04:55
  • found a good explanation from here: https://crypt.codemancers.com/posts/2018-06-07-frozen-middleware-with-rack-freeze/ – Oshan Wisumperuma May 19 '20 at 11:48