Using Rack::Builder with stateful applications

I was building a little app to help us monitor data changes on Songkick the other day, and was bitten by a feature of Rack that made it look like Faye wasn’t working. I was building a web stack like this, instead of using a config.ru file:

app = Rack::Builder.new do
  use Faye::RackAdapter, :mount => '/bayeux', :timeout => 25
  run Sinatra::Application
end

Rack::Handler.get('thin').run(app, :Port => 3000)

What the documentation doesn’t tell you is that Rack builds a brand new application object from the Builder config for every request. If one of your middlewares stores state in memory (as Faye does with for channel subscriptions), this state will be lost between requests and the app won’t work. To get around this, you need to do this to get a single instance of the built application to run:

Rack::Handler.get('thin').run(app.to_app, :Port => 3000)

That is, call to_app on your Rack::Builder instance to get a single application object to serve requests. This way, any in-memory state will persist between requests and your Faye app will be just fine.