tellemiller
Cache hit ratio on oban_jobs at 65% - large completed backlog, is this expected?
We recently started running Oban with Oban Web on PostgreSQL (AWS RDS gp3) and noticed our oban_jobs buffer cache hit ratio sitting at 65%, with ~600 block reads per second. We investigated and wanted to share findings and ask a few questions.
What we found
Our table has ~434k rows, of which 433,371 (99.97%) are in the completed state. We have max_age: 7 days configured on the Pruner. Table size is 301 MB, index size 229 MB (560 MB total). Autovacuum is healthy, dead tuples at 8.1%.
The main query we traced the block reads to was Oban Web’s queue typeahead suggestion:
SELECT DISTINCT o0."queue" FROM "public"."oban_jobs" AS o0
The composite index from v08, (state, queue, priority, scheduled_at, id), has state leading, so this query can’t use it efficiently and falls back to a large sequential scan. It’s worth noting, we also suspect some of our sequential scan count was inflated by developers running diagnostic queries during the investigation itself.
Actual performance metrics are all fine: avg read latency 0.6ms (peak 0.8ms), ReadIOPS at 650 of 3,000 available, 1.2GB freeable memory. So this isn’t causing a real problem today.
Questions
-
Is a 65% cache hit ratio on
oban_jobsexpected at this scale with a large completed backlog? Given our real metrics are healthy, is this simply a normal consequence of the table size relative toshared_buffers? -
We’re reconsidering our 7-day retention, but job retrospection is genuinely useful to us. What does effective pruning look like in production for teams that want to retain some history without the table growing unbounded?
-
For the Web typeahead query: queue names are statically defined in our config, so a full table scan to populate suggestions feels unnecessary. The
hint_query_limit(:queues)resolver callback seems like the right lever to limit the scan, but has aresolve_queuesstyle callback been considered, to allow serving suggestions directly from known config rather than the DB?
First Post!
sorentwo
That query would only run once every 5 minutes because it is cached locally. A sequential scan is expected in this case. Most of the typeahead queries, and the composite filters they help compse, aren’t index backed because they’re infrequent.
That’s entirely possible. Most of that data wouldn’t be accessed frequently under normal circumstances, and Oban will hit indexes for frequent queries.
The fewer jobs you retain, and the leaner you keep the table, the better performance you’ll have in general. One solution for keeping older jobs is DynamicPruner’s before_delete callback.
Active queues are vailable via Oban.Met.labels/1, or Oban.Met.checks/1, but queues you want to filter by aren’t always actively running. Or, you’re running multiple Oban instances that share a single database, or using Web to inspect Python jobs. In all of those cases, the database is the only real source of truth.
Popular in Troubleshooting
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









