85.1.40. pepsi-queue¶
inspect and repair the pepsi-ingress message queue
- Manual section:
1
85.1.40.1.1. Name¶
pepsi-queue - list, delete, re-stage and unstick messages in the work queue.
85.1.40.1.2. Synopsis¶
pepsi-queue [GLOBAL-OPTIONS] [list] [–json] [–state-only] [–headers] [–body] [–limit N] [–stage STAGE] [–status STATUS] [WORKQUEUE-ID]
pepsi-queue [GLOBAL-OPTIONS] delete WORKQUEUE-ID
pepsi-queue [GLOBAL-OPTIONS] set-stage WORKQUEUE-ID STAGE
pepsi-queue [GLOBAL-OPTIONS] clear-all
pepsi-queue [GLOBAL-OPTIONS] gc
The list options are accepted without the word list because listing is
the default action, but only then: given in front of another subcommand
(pepsi-queue --stage relay delete 5) they are refused, not silently ignored,
since they would read like a filter the command does not apply.
85.1.40.1.3. Description¶
pepsi-queue is a diagnostic and repair tool for the pepsi.workqueue table
shared by the Pepsi pipeline. Every accepted message advances through a filter
pipeline tracked by three columns on each row: a stage (the configuration
section of the program currently responsible for the message; init for a
freshly accepted message), a status (pending, running, paused,
failed or timeout), and an optional JSON state (per-stage scratch
data). See pepsi.state(7) for the keys state may carry.
The tool connects to the same database as the other components, through the
shared [pepsi-postgres] section; it introduces no configuration of its own.
When started as root it continues as the pepsi service account, which
owns the queue; see Running as root.
Warning
The mutating subcommands act immediately and are not reversible. delete removes a message permanently, and set-stage / clear-all change processing state in place.
set-stage and clear-all do emit a database notification: when they
moved at least one row they reset it to pending and then wake
pepsi-dispatch(1), so the change takes effect at once rather than at the
next poll. pepsi.workqueue carries no notifying trigger, and pepsi-queue
runs outside the dispatcher’s own loop, so nothing else would. delete
emits none — a row that is gone gives the dispatcher nothing to claim.
That makes clear-all unsafe on a running pipeline: it resets rows that are
currently running — a worker may still be handling one — and then hands
them straight back to the dispatcher, which claims them again. The message is
then processed twice, which for a delivery stage means a duplicate delivery and
for a bounce stage a duplicate bounce. Stop pepsi-dispatch first, or use it
only after a crash, when no worker is left to collide with.
85.1.40.1.4. Commands¶
- list [–json] [–state-only] [–headers] [–body] [–limit N] [–stage STAGE] [–status STATUS] [WORKQUEUE-ID]
List queued messages, ordered by
workqueue_id. This is also the default action when no subcommand is given, so thelistkeyword may be omitted:pepsi-queuelists everything andpepsi-queue 5shows only the message withworkqueue_id5.- WORKQUEUE-ID
An optional trailing message id. When given, at most that one message is shown.
--limitis then moot, but--stageand--statusare still applied on top of it, so a message that does not also match them is not shown.pepsi-queue 5andpepsi-queue list 5are equivalent.- –json
Emit a pretty-printed JSON array of objects (
workqueue_id,stage,status,mail_from,subject,received_at,state) instead of the human-readable table.subjectandstatearenullwhen the message carries neither.- –state-only
Print each matching message’s full, un-truncated JSON
state(the table view abbreviates it), one pretty-printed block per message, each headed by a# workqueue_idcomment line. With an explicit WORKQUEUE-ID that header is dropped and the output is just that message’s state, sopepsi-queue --state-only 5prints the completestateof message 5 — convenient to pipe into a JSON tool. A message with nostateprintsnull. This takes precedence over –json.- –headers, –body
Write the stored header block (–headers) or body (–body) of the message WORKQUEUE-ID to standard output, byte for byte and with nothing else printed; both together write the whole message — header block, the separating blank line, body — exactly as a stage that loads the full message reassembles it. Both need an WORKQUEUE-ID and cannot be combined with –json or –state-only. The output is raw mail (CRLF line endings, possibly 8-bit), meant for a file or a pipe, e.g.
pepsi-queue --headers --body 5 | pepsi-detect-language.- –limit N
Show at most N messages. Defaults to
100. Has no effect when an WORKQUEUE-ID is given, since at most one row can match.- –stage STAGE
Only show messages whose stage equals STAGE.
- –status STATUS
Only show messages with the given status.
- delete WORKQUEUE-ID
Permanently delete the message with the given
workqueue_id.- set-stage WORKQUEUE-ID STAGE
Re-assign the message to STAGE and implicitly reset its status to
pendingso the new stage picks it up. The message’sstateis left unchanged.- clear-all
Reset every message whose status is
runningorpausedback topending— the bulk “unstick” used after a crash or a stalled stage. Messages infailedortimeoutare left untouched.- gc
Garbage-collect the proof-of-origin nonce table (
pepsi.origin_nonce), deleting every entry whose two-week expiration has passed. An expired nonce can no longer authenticate a returning bounce, so dropping it is safe. The same run deletes the MX address cache rows (pepsi.dns_address) whose DNS TTL has passed: the relay stage never reads an expired row and replaces a host’s rows when it resolves it again, but a host it never resolves again would otherwise keep them for ever. Intended to run periodically; the Debian package ships apepsi-origin-gc.timerthat invokes it hourly. See pepsi-stage-relay-to-internet(1) and pepsi-stage-relay-to-smarthost(1) (which record the nonces as they relay) and pepsi-stage-anti-spam(1) and pepsi-stage-auto-pay(1) (which verify them).
85.1.40.1.5. Audit log¶
The three mutating subcommands are recorded in the shared audit log, through the
same helper the administrative API uses for the same actions: delete as
queue.cancel, set-stage as queue.set-stage (with the new stage) and
clear-all as queue.clear-all (with the number of rows reset). Moving a
message by hand is an administrative act whichever surface performs it, and a log
that saw only one of them would be misleading rather than merely incomplete.
list and gc are not recorded: reading is not an action, and the garbage
collector is a timer rather than an operator.
85.1.40.1.6. Running as root¶
Pepsi gives every component its own PostgreSQL role, authenticated over the local
socket by the operating-system account it runs as, and root is deliberately
not one of them. Rather than fail to connect and oblige you to remember
sudo -u pepsi pepsi-queue …, the tool detects that it was started as root
and becomes the unprivileged pepsi service account — the account the
dispatcher runs as, which owns pepsi.workqueue — before it connects. The change
is permanent for the life of the process; the tool needs no privilege of its own.
The configuration file (and any @inline-secret@ fragment it references) is
read before the switch, so a root-only configuration is still loaded normally.
If the pepsi account does not exist — an uninstalled source tree, a test rig —
the identity is left untouched, a warning is logged, and the connection is
attempted as the invoking user, so a setup in which root can reach the
database keeps working.
85.1.40.1.7. Global Options¶
These global options precede the subcommand (a trailing flag is rejected).
- -c FILE, –config FILE
Read the configuration from FILE instead of searching the default locations.
- -L LOGLEVEL, –log LOGLEVEL
Set the logging verbosity. LOGLEVEL is one of
error,warn,info,debugortrace(default:info).- -v, –verbose
Show log messages from all sources, including third-party libraries.
- -h, –help
Print a usage summary and exit.
- -V, –version
Print the version and exit.
85.1.40.1.8. Exit Status¶
- 0
Successful completion. An WORKQUEUE-ID that matches no row is not an error: list, delete and set-stage say so on standard output and still exit
0.- 1
An error occurred: a malformed configuration file or a failed database connection or query. The reason is written to the log.
85.1.40.1.9. Files¶
When –config is not given, the first existing file from the following list is used. Every Pepsi component shares the same configuration file, so this is the same list each one searches:
$XDG_CONFIG_HOME/pepsi.conf$HOME/.config/pepsi.conf/etc/pepsi/pepsi.conf/etc/pepsi.conf
85.1.40.1.10. Examples¶
List the first 20 queued messages as a table:
pepsi-queue -c /etc/pepsi/pepsi.conf list --limit 20
Show, as JSON, every message currently held by the spamfilter stage:
pepsi-queue -c /etc/pepsi/pepsi.conf list --json --stage spamfilter
Inspect just message 5, then dump its complete state JSON:
pepsi-queue -c /etc/pepsi/pepsi.conf 5
pepsi-queue -c /etc/pepsi/pepsi.conf --state-only 5
Save message 5 as it is stored, then look at its header block alone:
pepsi-queue -c /etc/pepsi/pepsi.conf --headers --body 5 > msg5.eml
pepsi-queue -c /etc/pepsi/pepsi.conf --headers 5
Hand message 42 to the spamfilter stage again:
pepsi-queue -c /etc/pepsi/pepsi.conf set-stage 42 spamfilter
Recover after a crash by re-queuing everything that was in flight:
pepsi-queue -c /etc/pepsi/pepsi.conf clear-all
85.1.40.1.11. See Also¶
pepsi-status(1), pepsi-config(1), pepsi-ingress(1), pepsi-dispatch(1), pepsi-failure-bouncer(1), pepsi.conf(5), pepsi.state(7), pepsi-setup(1)
85.1.40.1.12. Bugs¶
Report bugs to the Pepsi issue tracker.