NATS JetStream Subscribe

Consumes messages from a NATS JetStream stream. Source task — typically first in a flow.

Configuration

- nats_jetstream_subscribe:
    name: order_events
    credentials_path: /etc/nats/credentials.json
    url: "{{env.NATS_URL}}"
    subject: "orders.>"
    durable_name: order_processor
    stream:
      name: ORDERS
      subjects:
        - "orders.>"
      create_or_update: true

Fields

FieldTypeDefaultDescription
namestringrequiredTask name.
credentials_pathstringoptionalPath to NATS credentials file.
urlstringlocalhost:4222NATS server URL.
subjectstringrequiredSubject to subscribe to (supports wildcards).
durable_namestringDurable consumer name for persistent subscriptions.
streamobjectStream configuration (see below).
max_in_flightint64Messages in the flow at once. 1 keeps them in order.
max_messages_per_batchint200Most messages one pull request asks for. The subscriber asks only for as many as it has free max_in_flight slots.
max_ack_pendingintMax unacknowledged messages across every pod running the flow.
max_deliverintMax delivery attempts before discarding.
batch_expiresduration30sHow long each batch request waits on the server before returning empty. Prevents empty fetch loops.
delaydurationDeprecated and ignored. Use throttle to rate-limit individual messages.
throttledurationDelay between individual messages.
ack_timeoutdurationwait indefinitelyMax time a message may stay in the flow, from receipt. Also sets the consumer ack_wait.
depends_onlistUpstream task names.
retryobjectRetry configuration.

Stream options

FieldTypeDefaultDescription
namestringrequiredStream name.
subjectslistrequiredSubject patterns (supports wildcards).
create_or_updateboolfalseCreate or update stream if it does not match.
max_agedurationMax message age.
max_messagesintMax messages in stream.
max_bytesintMax stream size in bytes.
retentionstringlimitsRetention policy: limits, interest, work_queue.
discardstringoldDiscard policy: old, new.
discard_new_per_subjectboolfalseWhen true, rejects new messages if max_messages_per_subject limit is reached for that subject. Requires discard: new.
duplicate_windowdurationDeduplication window.

Delivery

A message is acked when every last task of the flow has finished with it. From receipt, also while it waits for a busy next task, the subscriber tells NATS the message is still in progress, so NATS doesn’t redeliver it. A message the flow holds for more than 5 minutes is logged as a warning every 5 minutes. A flow without a next task acks the message once it is read. A failed or timed-out flow asks NATS to redeliver the message after the redelivery delay. Delivery is at least once: a message can still arrive twice, for example after a pod stops mid-flow, so tasks with side effects should check an idempotency key.

When the flow stops or reloads, the messages it holds go back to NATS for immediate redelivery, and progress acks stop. If the subscriber ever stops reading while the flow runs, the flow fails and restarts.

Durable consumer

The subscriber creates the durable when it is missing. An existing durable gets the flow’s ack_timeout, max_deliver, max_ack_pending and max_waiting on start, and loses a backoff that older versions set. When NATS refuses the update, the subscriber logs a warning with the live and the flow’s values and keeps the durable as it is. A durable whose filter subject differs from subject fails the task; delete it or use another durable_name.

Output

FormatCrateDescription
JSON / Avro / Arrowasync-natsMessage payload from JetStream. Format depends on how the message was published.
Event fieldValue
event.subjectSubject the message was published to.
event.idThe Nats-Msg-Id header, when the message has one.
event.meta.headersMessage headers. A header set more than once keeps its first value.

Example

flow:
  tasks:
    - nats_jetstream_subscribe:
        name: orders
        credentials_path: /etc/nats/credentials.json
        subject: "orders.created"
        durable_name: order_processor
        max_ack_pending: 100
        stream:
          name: ORDERS
          subjects:
            - "orders.>"
          create_or_update: true
          retention: work_queue

    - script:
        name: transform
        code: |
          let order = event.data;
          #{id: order.id, total: order.amount}

    - log:
        name: output