perf(oban): move IEM-heavy queues off hot pods
Hot pods were running weather/narr/rtma/nexrad/contact_import alongside LiveView and the hourly propagation chain. The weather queue in particular hammers IEM with ASOS backfills; each Req retry against a 429 stacks an in-worker Process.sleep, and enough concurrent retries saturated the Ecto pool. Once DB checkouts started queueing past 15 s the cascade was always the same: Postgrex client timeouts → Oban.Notifier/Peer 5 s health checks failing → /health readiness timeout → kubelet flipping the pod out of the service endpoint set. One hot replica accumulated 11 restarts over 16 h. Split the shared queue block: anything that's truly per-QSO enrichment on demand (terrain, iemre, radar, mechanism, gefs, ionosphere, space_weather, admin, exports, backfill_enqueue) stays on both tiers, while weather/narr/rtma/nexrad/contact_import run only on prop-backfill. The hot pods mark those as paused so the queue entries still exist cluster-wide (Oban Pro's Smart engine rejects `limit: 0`). Cluster capacity for the backfill queues is unchanged; they just execute on the dedicated t620.
This commit is contained in:
parent
e4ed923986
commit
66fef4f6da
1 changed files with 31 additions and 15 deletions
|
|
@ -167,16 +167,33 @@ if config_env() == :prod do
|
||||||
]
|
]
|
||||||
|
|
||||||
shared_queues = [
|
shared_queues = [
|
||||||
# 1 slot per pod (3 cluster-wide). Any higher than this and the
|
|
||||||
# ASOS backfill hammers IEM hard enough to get HTTP 429s, which
|
|
||||||
# fill the retryable queue and thrash pod CPU without making
|
|
||||||
# forward progress.
|
|
||||||
weather: 1,
|
|
||||||
gefs: 1,
|
|
||||||
# :hrrr queue removed — per-QSO HRRR fetches flow through
|
# :hrrr queue removed — per-QSO HRRR fetches flow through
|
||||||
# hrrr_fetch_tasks and the Rust hrrr-point-worker (Phase 3 Stream C).
|
# hrrr_fetch_tasks and the Rust hrrr-point-worker (Phase 3 Stream C).
|
||||||
terrain: 3,
|
terrain: 3,
|
||||||
iemre: 3,
|
iemre: 3,
|
||||||
|
backfill_enqueue: 1,
|
||||||
|
admin: 1,
|
||||||
|
radar: 2,
|
||||||
|
ionosphere: 1,
|
||||||
|
space_weather: 1,
|
||||||
|
mechanism: 4,
|
||||||
|
exports: 1,
|
||||||
|
gefs: 1
|
||||||
|
]
|
||||||
|
|
||||||
|
# Queues that are only allowed to run on the dedicated backfill pod.
|
||||||
|
# Historical backfill (weather/narr/rtma/nexrad/contact_import) spins
|
||||||
|
# against rate-limited upstreams (IEM especially) and stacks Req
|
||||||
|
# exponential-backoff sleeps under its workers; running those slots
|
||||||
|
# on the hot pods was thrashing the DB pool and tripping the /health
|
||||||
|
# readiness probe. Keeping them on prop-backfill alone lets the hot
|
||||||
|
# pods serve LiveView + cron reliably while still processing
|
||||||
|
# enrichment cluster-wide.
|
||||||
|
backfill_only_queues = [
|
||||||
|
# 1 slot — see earlier note: any higher and the ASOS backfill
|
||||||
|
# hammers IEM hard enough to get HTTP 429s, which fill the
|
||||||
|
# retryable queue and thrash pod CPU without forward progress.
|
||||||
|
weather: 1,
|
||||||
# Historical backfill for pre-2014 contacts (pre-HRRR archive).
|
# Historical backfill for pre-2014 contacts (pre-HRRR archive).
|
||||||
# NARR is fetched anonymously from NCEI with no quota, no job
|
# NARR is fetched anonymously from NCEI with no quota, no job
|
||||||
# queue. Replaced the ERA5/CDS pipeline which never produced a
|
# queue. Replaced the ERA5/CDS pipeline which never produced a
|
||||||
|
|
@ -185,14 +202,7 @@ if config_env() == :prod do
|
||||||
# docs/plans/2026-04-15-merra2-historical-backfill.md.
|
# docs/plans/2026-04-15-merra2-historical-backfill.md.
|
||||||
narr: 6,
|
narr: 6,
|
||||||
rtma: 2,
|
rtma: 2,
|
||||||
backfill_enqueue: 1,
|
|
||||||
admin: 1,
|
|
||||||
nexrad: 2,
|
nexrad: 2,
|
||||||
radar: 2,
|
|
||||||
ionosphere: 1,
|
|
||||||
space_weather: 1,
|
|
||||||
mechanism: 4,
|
|
||||||
exports: 1,
|
|
||||||
contact_import: 4
|
contact_import: 4
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -203,6 +213,12 @@ if config_env() == :prod do
|
||||||
# each queue with `paused: true` (queue exists, processes nothing).
|
# each queue with `paused: true` (queue exists, processes nothing).
|
||||||
paused_queue = [local_limit: 1, paused: true]
|
paused_queue = [local_limit: 1, paused: true]
|
||||||
|
|
||||||
|
# Pause the backfill-only queues on hot pods so the queue exists
|
||||||
|
# (base config in config/config.exs declares it) but processes
|
||||||
|
# nothing here. Same `:paused` trick as disabled_hot_queues below.
|
||||||
|
paused_backfill_queues =
|
||||||
|
Enum.map(backfill_only_queues, fn {queue, _} -> {queue, paused_queue} end)
|
||||||
|
|
||||||
disabled_hot_queues = [
|
disabled_hot_queues = [
|
||||||
propagation: paused_queue,
|
propagation: paused_queue,
|
||||||
commercial: paused_queue,
|
commercial: paused_queue,
|
||||||
|
|
@ -212,8 +228,8 @@ if config_env() == :prod do
|
||||||
|
|
||||||
oban_queues =
|
oban_queues =
|
||||||
case prop_role do
|
case prop_role do
|
||||||
"backfill" -> disabled_hot_queues ++ shared_queues
|
"backfill" -> disabled_hot_queues ++ shared_queues ++ backfill_only_queues
|
||||||
_ -> hot_only_queues ++ shared_queues
|
_ -> hot_only_queues ++ shared_queues ++ paused_backfill_queues
|
||||||
end
|
end
|
||||||
|
|
||||||
cron_plugin =
|
cron_plugin =
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue