docs(compose): the app CPU cap cannot separate compression from the request path
The comment read "CPU ceiling for the two image workers + ffmpeg poster extraction", which describes a separation Docker cannot make: `compression.rs` runs that work in `tokio::task::spawn_blocking` — same process, same cgroup as every Axum handler — and `cpus`/`cpu_shares` are per-container. What actually happens is worth knowing when sizing this box: `cpu.max` is `120000 100000`, so two CPU-pegged blocking workers exhaust the 120 ms quota after ~60 ms of each 100 ms period and the kernel freezes the WHOLE cgroup — uploads, feed and SSE included — for the rest of it. Over a 100-photo burst that is ~210 s during which every request can eat up to 40 ms of throttle. The value stays at 1.2: an app that can take both cores starves Postgres, and every request path goes through Postgres. A slightly stalled request beats a starved database. The comment now says which knob actually shortens the backlog (COMPRESSION_WORKER_CONCURRENCY) rather than implying this one does.
This commit is contained in:
@@ -178,9 +178,22 @@ services:
|
||||
# Bounds a runaway ffmpeg transcode (large uploads, 2 workers) so it can't
|
||||
# OOM the single box and take down Postgres.
|
||||
memory: 1G
|
||||
# CPU ceiling for the two image workers + ffmpeg poster extraction. Bounded below
|
||||
# 2.0 so the app can never take both cores on its own.
|
||||
# CPU ceiling for the WHOLE app container. Bounded below 2.0 so it can never take both
|
||||
# cores on its own, which is what protects Postgres.
|
||||
# COMPRESSION_WORKER_CONCURRENCY=2 is the memory bound; this is the CPU one.
|
||||
#
|
||||
# It does NOT cap "the two image workers + ffmpeg" separately from the request path, as
|
||||
# this used to claim. `compression.rs` runs that work in `tokio::task::spawn_blocking` —
|
||||
# same process, same cgroup as every Axum handler — and `cpus`/`cpu_shares` are
|
||||
# per-container, so nothing here can tell them apart. Concretely: `cpu.max` is
|
||||
# `120000 100000`, so two CPU-pegged blocking workers exhaust the 120 ms quota after
|
||||
# ~60 ms of each 100 ms period and the kernel then freezes the ENTIRE cgroup — uploads,
|
||||
# feed and SSE included — for the remainder. Across a 100-photo burst (~210 s of
|
||||
# draining) every request in that window can eat up to 40 ms of throttle stall.
|
||||
#
|
||||
# Kept anyway: an app that can take both cores starves Postgres, and every request path
|
||||
# goes through Postgres. A slightly stalled request beats a starved database. If the
|
||||
# backlog needs to drain faster, the knob is COMPRESSION_WORKER_CONCURRENCY, not this.
|
||||
cpus: '1.2'
|
||||
# Half the default weight, and this is the ceiling's other half: the cap alone leaves
|
||||
# 0.8 vCPU for db + frontend + caddy, which frontend and caddy can consume between them.
|
||||
|
||||
Reference in New Issue
Block a user