Skip to content

Fatal interaction with the request_store gem and RACK_ENV #117

@Earlopain

Description

@Earlopain

Pardon the title but I don't really know how else to put it.

I use the request_store gem in my app and after deploying to production I immediatly noticed quite the issue (left is latency, the pink increase on the right is time spent in pg):
image

I only deployed to one of three hosts so the spike for that one is even more bad than this average shows. I've narrowed it down to the following code pattern:

module DeferredPosts
  extend ActiveSupport::Concern

  def deferred_post_ids
    RequestStore[:deferred_post_ids] ||= Set.new
  end

  def deferred_posts
    Post.includes(:uploader).where(id: deferred_post_ids.to_a).find_each.reduce({}) do |post_hash, p|
      post_hash[p.id] = p.minimal_attributes
      post_hash
    end
  end
end

This is included in the ApplicationHelper and will, over the span of one request, accumulate some model ids to later load all at once. It's never manually cleared as this would normally happen automatically.

What I observed is that every request increases the the set further, degrading performance even more. Eventually the database was saturating the network link of the host.

I can only reproduce under these circumstances:

  • Pitchfork is behind nginx
  • RACK_ENV is set to production

I have created a repro at https://github.com/Earlopain/pitchfork_repro and hope this will work for you. To get it up an running:

  • docker compose up nginx to start nginx. Will listen on port 3000 and proxy to port 8080.
  • RAILS_ENV=development RACK_ENV=production bundle exec pitchfork to start pitchfork. Note that RAILS_ENV=dev is only for convenience and not part of the repro.

You can then access the site at http://localhost:3000/test/demo. Refreshing should yield something like this:

Peek.2024-05-08.22-57.mp4

For some requests it will return the same set and then be empty on the next one. I don't really see ryhme or reason to when that happens. http://localhost:8080/test/demo which goes to pitchfork directly functions as expected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions