Skip to content

Queues, retries and the DLQ

The asynchronous endpoint: what happens between the submission and the 202, how retries are configured, what ends up in the dead-letter queue, and how to get it out again.

The asynchronous path

Terminal window
$ curl -i -X POST http://localhost:9090/flows/acme/forward-order/enqueue \
-H "Authorization: Bearer $NEXUS_KEY" \
-H 'Content-Type: application/json' \
-d '{"orderId":"A-1","total":42}'
HTTP/1.1 202 Accepted
Content-Type: application/json
{"queued":true,"offset":0,"tenant":"acme","flow":"forward-order"}

In order, before you get that response:

  1. A correlation ID is taken from X-Correlation-ID, then X-Request-ID, each only if valid, or generated when both are absent or invalid (the rule). A request the gate refuses is recorded under it too, and every answer, the 202 and the refusals alike, returns it in the X-Correlation-ID header. It is the ID stored in the queue frame, so it is the one the worker and the journal use.
  2. The access gate runs, before a byte of the body is read. The key is authenticated, the tenant checked, the flow allowlist and the rate limit applied. A caller refused here gets 401/403/404/429 without the body ever being pulled off the socket — so an unauthenticated caller announcing an oversized body is told 401, not 413. See Authentication.
  3. The message-size ceiling for this access point is resolved and the body is read under it.
  4. The signature is checked, if the server was started with NEXUS_WEBHOOK_SECRET set — after the body, because a signature is over the body. See Authentication.
  5. The body is parsed. JSON by default; an application/xml body is checked to be well-formed UTF-8 XML and queued as the text it was sent. It is parsed again at delivery, so the flow reads the same $ it would on /run. See JSON and XML.
  6. The message is appended to the queue’s write-ahead log and fsynced. Only then does the 202 go out.

The flow has not run at the point you get the response. offset is the message’s byte offset in the log — it is what identifies the message internally, not a handle you can query.

Nothing about the flow’s own behaviour is reported here. A flow that would have answered 422 on /run still answers 202 on /enqueue, and its failure surfaces later, in the log and eventually in the dead-letter queue.

Where it is stored

One log per (tenant, flow) pair, under the state directory. The log is a set of segment files: when the active one reaches queue_segment_max_bytes (see Server and configuration), the next message starts a new file. A file that is no longer the active one is removed once every message in it has been settled (see Housekeeping).

File Holds
queues/{tenant}/{flow}/segment.<16 hex digits>.log The messages, appended in order. The 16 digits are the byte offset at which the file starts, so the names sort in the order of the data. The file with the largest number is the one being written.
queues/{tenant}/{flow}/segment.log.ckpt Byte offset up to which everything has been processed.
queues/{tenant}/{flow}/segment.log.retry The pending retry schedule.
queues/{tenant}/{flow}/segment.log.seq The next message id. Durable, so ids keep counting across a drain and are never reissued.
queues/{tenant}/{flow}/dlq.log Dead-lettered messages.
queues/{tenant}/{flow}/dlq.log.acked Which dead-lettered messages you have already handled.

Each frame carries a checksum, and a frame that does not verify is not delivered.

A full segment is deleted once every message in it is settled. A message is settled when it was delivered, or when it was moved to the dead-letter queue (the dead-letter queue keeps its own copy). The platform removes such files oldest first and never the one it is writing to, so a queue with continuous traffic holds only the segments that still have a message in flight. A segment that still holds a message waiting for a retry stays, and so does every segment after it.

Upgrading from a version without segments. The first start renames the single segment.log of each queue to segment.0000000000000000.log, once, bytes unchanged. Nothing is split, lost or delivered twice. Going back is not supported: an older binary over a renamed directory creates an empty segment.log and delivers nothing. Drain the queue before downgrading, or restore the backup taken before the upgrade. The same holds for the message counter, which this version keeps in the queue’s lock file: an older binary would number new messages from a stale value.

Several hosts on one shared mount. A message enqueued on one host right after a rotation reaches the worker of another host only once that host’s NFS client sees the new segment. No message is lost and none is reordered. A worker that found its queue empty checks again after poll_interval_ms, then twice that, then four times that and stays there: at the default 500 ms, up to 2 seconds, so a message enqueued on another host can wait up to 2 seconds more for an idle reader. An idle worker costs about 0.6 RPC per second per idle flow per host on a shared mount (measured: 0.60 and 0.63; 1.83 without the back-off, about 3 times more), and the cost grows with the number of idle flows. Measured on two hosts, one NFSv4.1 mount, default options, 200 messages: a writer 10.6 RPC per message; a reader 1.5 to 1.6 RPC per message while the writer runs and 1.10 per message when it works through a backlog. After a crash or power loss up to 100 messages, or the messages acknowledged in the last 5 seconds, are delivered again.

Both path components are checked against the rule for a name that becomes a path before anything is created. A pair that breaks it — ../x, a name with a dot or an uppercase letter — is refused with an error naming the tenant, the flow and the character at fault, and no directory appears. This is the same rule the compiler applies at publication, so on a healthy installation it never fires; it exists for the paths that reach the queue without passing through publication: an operator’s nexus dlq replay --flow …, the Queue page of the UI, and an artifact published by a build that predates the rule.

The worker

A worker is a loop that dequeues, runs the flow, and acknowledges or reschedules. One worker per (tenant, flow). It is started on the first submission to that flow after the process starts, or by the process at start and every 5 seconds after, if the queue holds an undelivered message, and then runs until the process exits. While the queue is idle it polls after 500 ms, then 1 s, then every 2 s (at the default poll_interval_ms). If several server processes share a state directory, a lock file elects one of them to run the worker for each queue, and when it goes away another takes the queue over; see Running more than one engine.

After a restart, messages left unprocessed in a log are drained at start, with nothing submitted: the backlog goes first, in order.

The worker resolves latest when it picks a message up, so a message submitted before a deploy is executed by the version that is live when its turn comes. See Server and configuration.

Publishing from a flow

/enqueue is not the only way in. A step with the queue_publish effect puts the current message on another flow’s queue in the same tenant:

## Step: build-task
```ntd
{ "orderId": "{{ $.orderId }}", "requestedBy": "{{ ctx.correlation_id }}" }
```
## Step: hand-off
effects: [queue_publish]
queue: order-fulfilment
Key Required Meaning
queue yes The flow whose queue receives the message. A step without it is refused at compile time, and so is one whose value breaks the rule for a name that becomes a path

Three things follow from how effects work, and none of them is guessable:

  • The message is the previous step’s output. Effects run before the step body, exactly as they do for http_egress, so you build the payload in one step and publish it in the next. There is no payload template on the publishing step.
  • The tenant is the running flow’s tenant, never a key you can set. Cross-tenant publishing is not expressible.
  • The message must have a JSON form. queue_publish carries JSON only, so an XML document is refused naming the step, rather than being flattened into a shape the target flow cannot read back.

The correlation ID travels with the message, so the queued run continues the same trace.

The target is not checked at publish: publishing the flow that holds the queue_publish step succeeds whether or not its target exists. The check comes at run time. The publish fails — and the step fails with it — if no worker can be started for the target queue: for a target with no published flow, or because the residency budget is exhausted. That check happens before the write: a message in a queue nobody drains is a silent loss wearing the appearance of success.

The step fails like any other failed effect, so on a synchronous call the caller gets 502, or on a SOAP door 500 with soap:Server (SOAP 1.1) or soap:Receiver (SOAP 1.2) (see the response status). A publishing flow published before its target answers every such call this way while the target is not published. Publish the target flow first.

Retry configuration

Five front-matter keys, all optional: four for retries and one retention term.

Key Type Default Effect
queue_max_attempts integer 3 Total delivery attempts. On the attempt that reaches this number, the message is dead-lettered instead of rescheduled.
queue_initial_delay_ms integer 1000 Delay before the second attempt.
queue_backoff_factor number, at least 1.0 2.0 Multiplier applied per attempt. 1.0 gives a fixed delay.
queue_max_delay_ms integer 60000 Ceiling on any single delay.
queue_retention_hours integer, at least 1 none The longest a message may wait in the queue, in whole hours. 0 is refused at publish. When set, it overrides the installation’s term (queue_retention_hours in system_config). A message older than the term is not delivered: it moves to the DLQ with the reason expired, and stays there until it is replayed or discarded.

A queue_backoff_factor below 1.0 is rejected by nexus validate. A value that is not a number, for any of the five, is also rejected — a misspelled number does not silently fall back to the default.

The delay applied after a failed attempt n is:

delay = min(queue_initial_delay_ms × queue_backoff_factor ^ (n − 1), queue_max_delay_ms)

Worked example

---
flowmarkdown_version: "0.1"
flow: forward-order
tenant: acme
effects: [http_egress]
queue_max_attempts: 5
queue_initial_delay_ms: 500
queue_backoff_factor: 3.0
queue_max_delay_ms: 10000
---
## Step: forward
effects: [http_egress]
endpoint: https://orders.example.com/ingest
method: POST

With a downstream that is refusing every call:

Attempt Outcome Delay before the next attempt
1 fails 500 × 3⁰ = 500 ms
2 fails 500 × 3¹ = 1500 ms
3 fails 500 × 3² = 4500 ms
4 fails 500 × 3³ = 13500 ms, capped to 10000 ms
5 fails none — attempt 5 reaches queue_max_attempts, so the message is dead-lettered

Five attempts, four delays, 16.5 seconds of retrying. With the defaults it is three attempts, two delays (1000 ms and 2000 ms), and 3 seconds.

The schedule is written to disk on every reschedule, with absolute timestamps. A message whose next attempt is two minutes away survives a restart and is still two minutes away. A retry that came due while the process was down fires immediately.

The worker writes the schedule to disk before it takes the next message: a temporary file, flushed, then renamed over the old one, so the file on disk is always a whole schedule. If it cannot be written (a full disk, a permissions change), the worker stays on that message. It logs an ERROR nack: the retry schedule cannot be written — the queue holds this message until it can (defer: for a message held back by deduplication), repeated every minute, and tries again every second. Nothing else in that queue moves meanwhile. Once the write succeeds it logs a WARN the retry schedule is writable again — the queue moves on and carries on by itself.

If segment.log.retry does not parse, the queue is not opened. The worker does not start: the server logs an ERROR queue worker could not start; its messages stay queued and it is started again at most once every 5 s with error=failed to open queue: integrity failure for <tenant>/<flow>: the retry schedule <path> does not parse (…), once a minute while the file stays as it is, POST /enqueue to that flow answers 500, and nexus dlq replay fails with the same text. Opening on an empty schedule instead would lose, without a word, every message waiting for a retry. Other queues are not affected. To recover, with the platform stopped, move both segment.log.retry and segment.log.ckpt out of the queue’s directory, then start. Every message still in the segment files is delivered again from the first, so some are delivered twice and none is lost. On a flow with dedup_key:, while its key is remembered, a repeat of a message that ran without failing is acknowledged without running; one whose earlier execution still holds its claim on the key is held back, without spending an attempt; one that failed runs again, unless the flow sets dedup_on_failure: absorb, in which case it is acknowledged without running. Moving only segment.log.retry leaves the checkpoint past the messages that were waiting for a retry, and nothing delivers them again.

What reaches the dead-letter queue

Six things, each recorded with a reason:

Reason What happened
failed The flow failed on the attempt numbered queue_max_attempts.
failed The flow’s compiled artifact could not be read from the registry. Retried at a fixed one-second interval, three attempts, then dead-lettered. The flow’s own queue_max_attempts does not apply, because it is stored in the artifact that could not be read.
missing_flow Nothing is published for the tenant and flow, for instance after it was undeployed with nexus undeploy. It could never succeed, so it is dead-lettered on the first attempt. Messages left in the queue of a flow that is not deployed, retries included, reach the dead-letter queue at the next start or within 5 seconds, with no worker running.
integrity The stored compiled flow failed its integrity check. Re-reading the same bytes cannot produce a different result, so it is dead-lettered on the first attempt.
integrity A frame in the queue’s own log is not a message: its checksum verifies, but its bytes do not parse. Dead-lettered on the first attempt, with the bytes kept as base64 in the payload and the frame’s position in the last error. Replaying it reads the bytes again, and is refused if they still do not read as a message for this queue.
expired The message was older than its term (queue_retention_hours of the flow, else of the installation) when the worker took it, so it was not delivered. A message is judged when the worker takes it: one waiting for a retry is judged when the retry falls due. last_error names the time it was accepted and the term. Replaying it gives it a fresh term.

One thing that looks similar and does not: a condition fence that evaluated to false. The message is acknowledged and dropped. This is a filter, not a failure — it is recorded as queue_filtered and never retried. See Routing and validation.

A message is removed from its queue only once its dead-letter entry is written to disk. If the dead-letter queue cannot be written (a full disk, a permissions change), the message stays in its queue and is tried again after queue_max_delay_ms (the default, 60 s, when the flow’s artifact could not be read), without spending an attempt, and the worker logs an ERROR DLQ write failed — message deferred, not acked. It appears in nexus dlq list, in the audit log and as a dlq_moved event only once the write succeeds.

A dead-lettered entry keeps the payload as submitted, the message’s id, when it was enqueued, when it was dead-lettered, how many attempts it consumed, the reason, and the text of the last error. It also keeps the correlation ID, which list shows; the dlq_moved event in the structured log carries it too. See Logging and audit.

An integrity entry for a frame that did not parse has a new id and no enqueue time: both were inside the bytes that did not parse. Its last error names the kind of fault and the line and column, never a byte of the frame; entries written by v1.2.0 and v1.3.0 may still quote a value and are not rewritten. nexus dlq list marks such an entry raw_frame: yes. Replaying it reads the frame again: if this version now reads it as a message for the same queue, the original message goes back on the queue, not its base64 text. If it still does not, the replay is refused and the entry stays (see Replaying). In that case decode the payload to see what was written, have the sender send the message again if it was one, then discard the entry.

Managing the dead-letter queue

Listing

Terminal window
$ nexus dlq list
DLQ: 2 pending message(s)
id=7 tenant=acme flow=forward-order
enqueued_at: 2026-08-09T14:02:11Z
failed_at: 2026-08-09T14:02:14Z
attempts: 3
reason: failed
correlation_id: "c-2f81"
last_error: step 'forward': effect handler failed: HTTP 503 Service Unavailable
id=2 tenant=acme flow=sync-invoices
enqueued_at: 2026-08-09T09:41:00Z
failed_at: 2026-08-09T09:41:07Z
attempts: 3
reason: failed
correlation_id: ""
last_error: step 'check': validation failed (Semantic): total must be positive

Both filters are optional and can be combined:

Terminal window
$ nexus dlq list --tenant acme
$ nexus dlq list --tenant acme --flow forward-order

An empty dead-letter queue prints DLQ is empty.

Replaying

Terminal window
$ nexus dlq replay --tenant acme --flow forward-order --id 7
replayed id=7 tenant=acme flow=forward-order

The payload is appended to the main queue as a new message, at the back, and the dead-letter entry is marked handled so it no longer appears in list. The replayed message starts again at attempt 1 with the full retry budget, and it runs against whatever version is latest when the worker reaches it. On a flow with dedup_key: it is claimed like any delivery while the key is remembered: it is acknowledged without running if a delivery of the same key has finished without failing since, or if the key’s last execution failed and that version sets dedup_on_failure: absorb; when that version keeps the default retry, a failure lets it run again (Deduplication).

An entry for a frame that did not parse is read again first. If the frame now reads as a message for the same tenant and flow, that message is what goes back on the queue. If it does not, the command exits with status 1, changes nothing, and the entry stays in the dead-letter queue:

Terminal window
$ nexus dlq replay --tenant acme --flow forward-order --id 12
error: DLQ entry 12 for acme/forward-order was not replayed: its frame is not a queue message (line 1, column 33). The entry stays in the DLQ.

The message never names a byte of the frame. The dead-letter page of the management UI refuses the same replay with an alert and leaves the entry listed as an unreadable frame.

A replayed message keeps its correlation ID: the dead-letter entry stores the ID the message had, and the replay puts it back. The log page finds the original run and the replay under the same ID. An entry written before the platform stored the ID has none to keep: it is replayed with an empty one, list shows correlation_id: "", and the worker gives the message a new ID.

Replay writes to the log; it does not run the flow. Something has to pick the message up. If a worker is already running for that flow it will be dequeued within the poll interval; if none is, an engine starts one at its next 5-second pass, because the queue now holds an undelivered message. The replayed message is therefore delivered within about 5.5 seconds on a local disk. That bound is not stated for a queue directory on a network file system.

Fix the cause first. Replaying into a downstream that is still returning 503 spends the retry budget again and puts the message straight back.

Discarding

Terminal window
$ nexus dlq discard --tenant acme --flow forward-order --id 7
discarded id=7 tenant=acme flow=forward-order
the body leaves the disk at this flow's next queue drain; until then it is only hidden from listings

Marks the entry handled without re-running anything. It is gone from list at once, and there is no command to bring it back.

The payload is deleted in two stages, and the gap matters if you are discarding a message because of what it contains. The command writes the id to dlq.log.acked; the flow’s worker rewrites dlq.log without the marked rows the next time it finds the queue empty — seconds on a queue with traffic. Two things to know about the gap:

  • A flow with no running worker never closes it. A worker starts when the queue holds an undelivered message, at start or on a submission. A flow whose queue is empty has none, so nobody applies its marks until a message arrives. nexus dlq list will show the entry gone while dlq.log has not shrunk.
  • A restart does not lose the mark. dlq.log.acked is durable; the rewrite happens at the first drain after the platform comes back.

To delete immediately, stop the platform and remove {queue_dir}/{tenant}/{flow}/dlq.log together with dlq.log.acked. That also takes the entries nobody marked.

Flags

Flag list replay / discard
--tenant <t> optional filter required
--flow <f> optional filter required
--id <n> — required, from nexus dlq list
--db <path> optional optional

An id is unique within one (tenant, flow) queue, not across queues — which is why replay and discard need all three. --tenant and --flow are checked against the rule for a name that becomes a path before the queue directory is opened: a value like ../x exits non-zero, names the offending pair, and creates nothing.

--db defaults to ~/.nexus/registry.db. The queue directory is derived from it, so if you started the server with a non-default --db, pass the same path here or you will be looking at an empty dead-letter queue in the wrong directory.

The Queue page of the management UI shows the same entries and has replay and discard buttons for them. See Logging and audit.

Delivery semantics

At-least-once. That is the whole guarantee.

The checkpoint only advances after a message has been processed successfully. Everything between the checkpoint and the end of the log is delivered again when the process starts, so a crash between “the flow ran” and “the checkpoint moved” produces a second delivery of a message whose effects already happened. A retry is the same thing by design: the flow restarts from step one with the original payload, and every step that succeeded last time runs again, effects included.

The window is up to 100 messages or 5 seconds. The checkpoint is written in batches, not once per message, so that a queue on a network disk does not pay a file rewrite for every message. A crash or a power loss delivers again up to 100 messages, or the messages acknowledged in the last 5 seconds, whichever is fewer; none is lost. A clean stop writes the checkpoint first, so acknowledged messages are not delivered again. A flow whose steps are not safe to repeat defends itself with an idempotency key, or with dedup_key: and the deduplication store (see What you must do to be safe under redelivery). Until the checkpoint is written, the Queue page and the dashboard can show a count that is up to 5 seconds behind.

Order is FIFO on first delivery only. Within one queue, messages are delivered in the order they were submitted. A message that is rescheduled loses its place — it comes back when its delay expires, after messages that were submitted later. Do not build anything that depends on two messages arriving in a fixed order.

Each queue is independent. No ordering between flows, no ordering between tenants, no shared throughput.

What you must do to be safe under redelivery

Assume every message will be delivered more than once, because eventually one will be.

The platform’s guarantee stops at at-least-once; exactly-once is built at the destination, not declared on the platform. The pattern is the idempotent receiver: the message’s identifying key travels with it, and the destination recognises the second arrival and refuses it. On the platform’s side there are three dials, and all three belong to the flow: how often to retry — only as the flow’s own retry configuration says, nothing retries by default beyond it — what counts as delivered, and whether a repeat of a key runs at all. On a flow that declares dedup_key:, while the key is remembered, a message is acknowledged without running once an earlier execution of its key finished without failing, held back, without spending an attempt, while that execution still holds its claim on the key, and run again after a failure, unless the flow sets dedup_on_failure: absorb, in which case it is acknowledged without running (Deduplication).

  • Give the downstream something to deduplicate on. Send a key it can recognise as a repeat — an order number, an invoice id, the correlation ID — and let it reject or ignore the second arrival.

    ## Step: forward
    effects: [http_egress]
    endpoint: https://orders.example.com/ingest
    method: POST
    headers: {"Idempotency-Key": "{{ ctx.correlation_id }}"}

    The correlation ID is stored in the queue frame, so it is the same on every attempt of the same message — which is what makes it usable for this. A replay keeps the ID too, so it sends the same key: a backend that remembers keys treats the replay as a duplicate of the first run.

  • Define “delivered”, when a 2xx is not enough. By default a non-2xx from the backend fails the step — which is exactly what triggers the retry, the backoff, and at queue_max_attempts the dead-letter queue. When the backend answers 200 with its verdict in the body, write the condition as a validate step after the egress. On a 2xx the backend’s response is the current document, so the rule reads it as $.:

    ## Step: forward
    effects: [http_egress]
    endpoint: https://orders.example.com/ingest
    method: POST
    headers: {"Idempotency-Key": "{{ ctx.correlation_id }}"}
    ## Step: accepted-means-accepted
    ```validate
    $.status == "ACCEPTED" | "backend did not accept the message"
    ```

    A failed rule fails the delivery like any other error: retry with backoff, dead letter at the limit. The message is not delivered until the backend says so, in the form the flow declared.

    Unless the flow has a ## Fault: section. A handler that succeeds becomes the delivery’s answer, so the delivery ends in success and the worker acks the message: no retry, no backoff, no dead letter. That is the whole point of a fault handler on the synchronous door, and it is the opposite of what you want here — the message you wanted parked for a human is gone instead, with queue_processed in the log and nothing in the dead-letter queue. The one thing that tells them apart is the outcome column on that row, which reads fault_handled rather than succeeded.

    So on a queued flow, decide which of the two you are writing. A handler that turns a rejection into a notification and lets the message go is a deliberate policy; a handler you added for the synchronous door and forgot about is a silently disarmed dead-letter queue. If you need both — a handled answer and the retry — the handler has to fail: end it with a step that errors, and the delivery stays failed.

  • Derive keys from the payload, never from the clock or a random value. uuid() and now() produce a new value on every attempt, so a key built from them defeats the deduplication it was meant to enable. $.orderId does not.

  • Prefer effects that are safe to repeat. A PUT that sets a record to a known state is safe to run twice; a POST that appends a row is not.

  • Do not spread one logical operation across several steps and assume it either all happened or none of it did. There are no transactions across steps. A flow that fails at step 4 re-runs steps 1 to 3, effects included, on the next attempt. Under dedup_key: with dedup_on_failure: absorb there is no next attempt: the worker acknowledges the failed message instead of retrying it.

Housekeeping

A queue reclaims its own space. When its worker finds nothing left to deliver and no retry pending, it empties its segment in place and rewrites dlq.log without the entries you discarded or replayed. Nothing is deleted while the worker holds the files open, so this is safe on a live installation.

A queue with no running worker — nothing undelivered in it, so no engine has started one — is handled differently: a background task deletes its files outright, and the next submission recreates them. That task refuses to touch a queue that still has messages, pending retries, or unhandled dead letters.

One consequence to expect on the queues page: total drops to zero after a drain, and falls whenever a segment is removed. It counts what is in the segment files now, not what the queue has ever carried. The history is in the structured log. What survives a drain is the message id, which keeps counting from a durable counter and is never reissued. See Server and configuration.

What stays on disk from a queued message

A message body sits in a segment.<offset>.log file as plaintext JSON inside a checksummed frame. The checksum is integrity, not a cipher: it says whether the bytes rotted, and it hides nothing. Masking does not reach the queue either. It is applied when a payload is recorded in the log or in a trace, on JSON object keys, and the body written to a queue never passes through it.

Acknowledging moves the checkpoint, and a full segment is deleted after it. Acknowledging a message moves the checkpoint in segment.log.ckpt forward, written within 100 messages or 5 seconds of the acknowledgement (see Delivery semantics). A segment that is no longer the one being written is removed once the checkpoint is past its last message and nothing in it is waiting for a retry. The segment being written stays, in the clear, until the queue empties: the queue’s worker finds nothing left to deliver and no retry pending, and empties it; or the queue has no running worker and nothing left in it, and the background task deletes its files (see Housekeeping). Each removal is recorded as a queue.segment.retired audit row. There is no time limit and no expiry: a message stays on disk for as long as it is unsettled or its segment is the one being written.

There is no erasure of one specific message on request. The only per-message deletion is discarding a dead letter, with nexus dlq discard or from the Queue page of the UI. It acts on the dead-letter copy in dlq.log, not on the original in segment.log, and takes effect at the next drain (see Discarding).

Not supported

Topic fan-out to several flows from one submission, priority ordering within a queue, and cross-node replication of a queue.