#2822·capybara

Puma backlog is not drained and requests slip through between tests.

Author: mikzCreated Aug 28, 2025Updated Jul 14, 2026

I was debugging CSRF exceptions in our test suite when running on a resource starved machine with just 1 puma thread.

It turned out a combination of fetch calls in setTimeout and puma not processing requests fast enough lead to requests leaking in between tests and producing CSRF exceptions.

Not sure exactly why or how it slips through the middleware - maybe there is a successful check before puma accepts more requests from the backlog.

In my testing this pretty basic monkeypatch fixes the issue and drains all the requests in between tests.

ruby
module CapybaraWaitForPumaBacklog
  extend ActiveSupport::Concern

  prepended do
    class_attribute :wait_for_pending_puma_backlog, default: true
  end

  def pending_requests?
    super || puma_backlog_pending?
  end

  def puma_backlog_pending?
    wait_for_pending_puma_backlog && puma_backlog > 0
  end

  private

    def find_puma_server
      @_puma_server ||= ObjectSpace.each_object(::Puma::Server).find(&:running)
    end

    def puma_backlog
      server = find_puma_server
      server ? server.backlog : 0
    end
end

Capybara::Server::Middleware.prepend(CapybaraWaitForPumaBacklog)

I'd like to contribute to capybara not exactly this, but rather a Puma plugin that would produce the same result and extend Capybara::Server#pending_requests? to check the server plugin in addition to the middleware. I don't have the exact design worked out yet.

Is that something worth contributing? I think it could remove some flakiness for people.