LRFalk01
LRFalk01

Reputation: 981

Rails DB Connection Pool Hydration

I'm working on a Rails 7 app with some pretty tight response time SLAs. I am well within SLA during normal runtime. Where I fall painfully short is first request. I've added an initializer that will load up ActiveRecord and make sure all of my DB models are loaded. It hydrates some various memory caches, etc. This took me pretty far. My first response time was reduced about 60%. However, I've been trying to figure out a couple things are are still slowing down first response time.

  1. First API request does a check to see if I need to do a rails migration. I've not figured out how to move this check to init.
  2. First API request appears to be be using a fresh DB Pool.. not the one that was used in init phase. I've tried fully hydrating the pool to spare the API from creating them when Rails kicks on, but I've not figured it out.

In an initializer I can do something like this:

connections = []
ActiveRecord::Base.connection.pool.size.times do
  connections << ActiveRecord::Base.connection.pool.checkout
end

connections.each { ActiveRecord::Base.connection.pool.checkin(_1) }

According to my PG logs, this opens up the connections and Rails does all of this typing queries, setting session properties, etc. However, when I go to fire off my first API call, my pool is empty.

Upvotes: 1

Views: 226

Answers (1)

LRFalk01
LRFalk01

Reputation: 981

In the end what ended up being the general issue was I needed to be hydrating the pool with the correct connections. on_worker_boot is because this is running behind puma.

on_worker_boot do
  ActiveRecord::Base.connected_to(role: :reading) do
    # spin up db connections
    connections = []
    (ActiveRecord::Base.connection.pool.size - 1).times do
      connections << ActiveRecord::Base.connection.pool.checkout
    end

    connections.each { |x| ActiveRecord::Base.connection.pool.checkin(x) }
  end
end

Upvotes: 2

Related Questions