23. pepsi-dispatch¶
The single long-lived coordinator that drives messages through the stages.
23.1. Role¶
pepsi-dispatch is the only process that starts stage programs. Run exactly
one per system. It claims newly queued rows and feeds each to an idle worker
process of the row’s stage, requeues advanced messages for the next stage, and
recovers from crashes and timeouts. It processes no message content itself.
Reference: pepsi-dispatch(1).
23.2. Features¶
Event-driven, batched claiming.
LISTENs on theingresschannel with a periodicPOLL_INTERVALheartbeat. On any wake it drains its pending internal events (so per-stage capacities are current) and then claims work for every stage with spare capacity in oneUPDATE … RETURNING— each stage up to its own remaining capacity (a per-stageLATERAL … ORDER BY ingress_id LIMIT capthat stops at the cap via the partialpendingindex). With exactly one dispatcher claiming serially as the solepending``→``runningwriter, the claim needs noFOR UPDATE SKIP LOCKED.Persistent, pipelined workers. Each stage runs
PROGRAM worker(found onPATHunless absolute) as long-lived processes that connect to the database once and read message ids from standard input, answering with a one-line status (0on success) per message, in order. A worker is handed up toQUEUE_LIMITids at once (written to its stdin in a single buffer); it processes them strictly serially, but the next id is already queued, removing a coordinator round-trip per message. A stage’s in-flight capacity is thereforeQUEUE_LIMIT × PARALLELISM, and because the worker count is unchanged it costs no extra database connections.Elastic per-stage pools. Workers are started on demand up to a stage’s
PARALLELISM; work is packed onto the fewest workers, and surplus workers are stopped afterWORKER_IDLE_TIMEOUT— so a quiet stage collapses toward zero workers and a busy one grows to its cap. AfterMAX_MESSAGESa worker recycles its child (once its pipeline drains); a stage whosePROGRAMcannot start is held off with a short cooldown instead of spinning.Requeue on advance. When a worker reports success leaving the row
runningat a new stage (it advanced), the dispatcher requeues it topendingso the next stage’s pool picks it up (no in-process chaining).Retry scheduling. Sleeps until the earliest
pausedrow’stimeout(or a due worker reap / spawn cooldown / the heartbeat), then flips due rows back topendingand re-scans.Crash & watchdog recovery. A worker that reports non-zero fails that one message and survives; a crashed child fails its head-of-line message, and a head-of-line message unanswered within
MAX_RUNTIME(timed from when it reached the head) →timeout. In the crash and timeout cases the worker’s other pipelined messages never ran and are requeued topendingrather than lost. Reasons are written tostate.dispatch_errorunder astatus = 'running'guard so a stage that already transitioned the row is never clobbered.Start-up / shutdown safety. Resets orphaned
runningrows (from a previous dispatcher) topendingon start; onSIGINT/SIGTERMstops workers and resets their (and any claimed-but-unassigned) rows.Isolation. At most one writer ever touches a given queue row, so the shared pool runs
READ COMMITTED; queue operations are still wrapped in a retry helper that re-runs a transient40001/40P01failure as cheap insurance.Config propagation. Passes
CONFIG_FILEto workers via-cso they load the same configuration.Statistics. Accumulates per-stage throughput, kills/timeouts, crashes and processing time plus the global stage/message totals in memory, and flushes the deltas to the
stage_stats/dispatch_statstables in a single transaction everySTATS_INTERVAL, whenever the pipeline goes idle (at most once a second, so a finished burst’s numbers do not wait for the next tick), and on shutdown; nothing is written when there are no deltas. It is the only writer of those tables — stages fused into another stage’s worker pass are reported back on that pass’s status line instead of being written by the worker, which keeps every worker of a stage from contending for that stage’s single row. These are exported by pepsi-httpd’s/metrics.
23.3. Configuration¶
[pepsi-dispatch]: MAX_RUNTIME (default 300 s), WORKER_IDLE_TIMEOUT
(default 5 s), POLL_INTERVAL (default 30 s), STATS_INTERVAL (default 60 s),
CONFIG_FILE. Per-stage worker pools are sized by PARALLELISM (default 4),
QUEUE_LIMIT (default 4, the messages pipelined to one worker at once) and
MAX_MESSAGES (default 1000) in each [stage-<name>] section. See
pepsi.conf(5) and Configuration.
23.4. See also¶
Architecture, pepsi-queue, pepsi-ingress, pepsi-dispatch(1).