Skip to main content

Notifications configuration

[notifications]​

Delivering notifications, evaluating live changes, and draining periodic subscriptions.

[notifications.delivery]​

How notifications reach their subscribers, the queue that carries them and how long finished deliveries are kept.
[notifications.delivery]
mode = "live"
request_timeout = "10s"
max_concurrent = 20
max_error_length = 1024
private_addresses = "allowed"
allowed_addresses = []
denied_addresses = []
max_http_body = "128 MiB"
max_mqtt_packet = "128 MiB"
max_attempts = 5

notifications.delivery.mode​

stringrestart to apply

Whether notifications are sent from memory ("live") or through a queue in the tenant database ("durable").

Default
"live"
Allowed values
"live"Subscriptions are evaluated and notifications sent from memory, without persistence, retry or dead-lettering; a crashed broker loses the notifications still in flight. Deliveries already queued in the tenant database are still drained, with their retries.
"durable"Every notification is written to the durable queue in the transaction that raised it, and sent by a worker with retry, leasing and dead-lettering.
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__MODE

notifications.delivery.request_timeout​

non-zero durationrestart to apply

The longest an outgoing notification may take before it is abandoned, live or queued. A subscription's own timeout can shorten it but not lengthen it.

Default
"10s"
Must be
0 < request_timeout
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__REQUEST_TIMEOUT

notifications.delivery.max_concurrent​

positive integerrestart to apply

The most notifications one tenant sends at once, shared by all its Subscriptions. A delivery pass keeps this many in flight while the queue holds due deliveries. Once one Subscription holds half the slots, a freed slot goes to the due Subscription with the fewest in flight, and while another Subscription is active, with a notification in flight or one answered within notifications.delivery.request_timeout, the one holding half gets no more. A slow endpoint therefore leaves the others at least half the slots, and a failing one holds a single slot for its retry. A Subscription active on its own uses every slot.

Default
20
Must be
0 < max_concurrent ≤ 1024
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__MAX_CONCURRENT

notifications.delivery.max_error_length​

positive integerrestart to apply

The most characters of a failure diagnostic kept with a failed delivery attempt. It may be raised to the longest failure summary the store keeps.

Default
1024
Must be
0 < max_error_length ≤ 2048
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__MAX_ERROR_LENGTH

notifications.delivery.private_addresses​

stringrestart to apply

Whether a notification endpoint (an HTTP URL or an MQTT server) resolving into private or reserved address space is notified. Checked against the address actually resolved, not the host name. notifications.delivery.allowed_addresses exempts addresses from "refused", and notifications.delivery.denied_addresses refuses addresses whatever this is set to. Allowed by default because subscribers and MQTT servers commonly run on the broker's own private network; set "refused" when clients you do not trust create subscriptions.

Default
"allowed"
Allowed values
"allowed"Any endpoint the broker's network reaches is contacted.
"refused"An endpoint whose resolved address is loopback, private or reserved is refused, so a client-supplied endpoint cannot aim the broker at internal hosts. The refusal is recorded as a failed request.
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__PRIVATE_ADDRESSES

notifications.delivery.allowed_addresses​

list of stringrestart to apply

IP addresses and subnets ("10.2.0.0/24", "10.3.0.17", "fd00:1234::/48") that a notification endpoint (an HTTP URL or an MQTT server) may resolve into even though notifications.delivery.private_addresses is "refused". Empty by default. An entry in notifications.delivery.denied_addresses takes precedence.

Default
[]
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__ALLOWED_ADDRESSES

notifications.delivery.denied_addresses​

list of stringrestart to apply

IP addresses and subnets ("203.0.113.0/24", "198.51.100.9") that a notification endpoint (an HTTP URL or an MQTT server) must not resolve into, public ones included and whatever notifications.delivery.private_addresses is set to. Empty by default. Takes precedence over notifications.delivery.allowed_addresses.

Default
[]
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__DENIED_ADDRESSES

notifications.delivery.max_http_body​

sizerestart to apply

The largest notification body sent over HTTP. A larger notification is not sent, and its delivery fails without a retry, since every attempt would send the same body. A notification carries the entities of a change in full, so a limit at request_limits.max_body or below could refuse to notify an entity one request wrote.

Default
"128 MiB"
Must be
request_limits.max_body < max_http_body
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__MAX_HTTP_BODY

notifications.delivery.max_mqtt_packet​

non-zero sizerestart to apply

The largest MQTT packet a notification is published in, envelope and topic included. It is also the largest packet the broker accepts from an MQTT server. When an MQTT 5 server announces a smaller maximum, that maximum applies on its connection. A larger notification is not published, and its delivery fails without a retry. A notification carries the entities of a change in full, so a limit at request_limits.max_body or below could refuse to notify an entity one request wrote. No packet is longer than 256 MiB, so request_limits.max_body stays below that.

Default
"128 MiB"
Must be
0 < request_limits.max_body < max_mqtt_packet ≤ 256 MiB
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__MAX_MQTT_PACKET

notifications.delivery.max_attempts​

positive integerrestart to apply

The attempts a queued notification gets. A delivery that has failed this many times is dead-lettered and kept for notifications.delivery.retention.dead_letter_after, as a record of a notification that never arrived.

Default
5
Must be
0 < max_attempts ≤ 2147483647
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__MAX_ATTEMPTS

[notifications.delivery.queue]​

How the delivery queue is polled, claimed and retried. A failed delivery is retried on a delay that doubles from notifications.delivery.queue.retry_interval up to notifications.delivery.queue.max_retry_interval.
[notifications.delivery.queue]
poll_interval = "1s"
max_poll_interval = "30s"
lease_timeout = "30s"
retry_interval = "5s"
max_retry_interval = "5m"

notifications.delivery.queue.poll_interval​

non-zero durationrestart to apply

How soon an idle worker polls again once a commit's wake has been handled: the floor of its idle backoff. A commit in the same broker process wakes the worker at once.

Default
"1s"
Must be
0 < poll_interval
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__QUEUE__POLL_INTERVAL

notifications.delivery.queue.max_poll_interval​

durationrestart to apply

The longest the idle backoff grows to while no commit wakes the worker. Also how soon a job committed by another broker process is picked up.

Default
"30s"
Must be
notifications.delivery.queue.poll_interval ≤ max_poll_interval
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__QUEUE__MAX_POLL_INTERVAL

notifications.delivery.queue.lease_timeout​

non-zero durationrestart to apply

How long a claim keeps a job from every other worker. A worker that dies leaves its jobs unclaimable for the rest of the term. It is applied in whole seconds, rounded down.

Default
"30s"
Must be
0 < notifications.delivery.request_timeout + 5s ≤ lease_timeout ≤ 1day
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__QUEUE__LEASE_TIMEOUT

notifications.delivery.queue.retry_interval​

non-zero durationrestart to apply

The delay before a failed job's first retry. Each later retry waits twice as long as the one before, up to the longest retry delay.

Default
"5s"
Must be
0 < retry_interval
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__QUEUE__RETRY_INTERVAL

notifications.delivery.queue.max_retry_interval​

durationrestart to apply

The longest a retry delay grows to.

Default
"5m"
Must be
notifications.delivery.queue.retry_interval ≤ max_retry_interval
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__QUEUE__MAX_RETRY_INTERVAL

[notifications.delivery.retention]​

How long finished deliveries and their change events are kept.
[notifications.delivery.retention]
acknowledged_after = "1day"
dead_letter_after = "7days"
orphan_event_after = "1day"
sweep_interval = "5m"

notifications.delivery.retention.acknowledged_after​

non-zero durationrestart to apply

How long a delivered notification is kept.

Default
"1day"
Must be
0 < acknowledged_after
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__RETENTION__ACKNOWLEDGED_AFTER

notifications.delivery.retention.dead_letter_after​

non-zero durationrestart to apply

How long a delivery that ran out of attempts is kept, as a record of a notification that never arrived.

Default
"7days"
Must be
0 < dead_letter_after
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__RETENTION__DEAD_LETTER_AFTER

notifications.delivery.retention.orphan_event_after​

non-zero durationrestart to apply

How long a change event no delivery refers to any more is kept.

Default
"1day"
Must be
0 < orphan_event_after
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__RETENTION__ORPHAN_EVENT_AFTER

notifications.delivery.retention.sweep_interval​

non-zero durationrestart to apply

How often expired deliveries and events are removed. A pass runs only for a tenant that may have written since the last one.

Default
"5m"
Must be
0 < sweep_interval
Environment variable
ANDROMEDA__NOTIFICATIONS__DELIVERY__RETENTION__SWEEP_INTERVAL

[notifications.evaluation]​

How live delivery evaluates committed entity changes.
[notifications.evaluation]
max_queued_changes = 8192
max_concurrent_changes = 32
drain_timeout = "30s"

notifications.evaluation.max_queued_changes​

positive integerrestart to apply

The most committed entity changes each tenant buffers for live evaluation. While the broker runs no change is dropped: once the buffer is full, a write waits after its commit until evaluation makes room, so a burst larger than the buffer slows the tenant's writes instead of losing notifications. Changes still waiting when the broker stops or the tenant is unloaded are evaluated first, within notifications.evaluation.drain_timeout. A full buffer holds under 4 MB per tenant at the default. "durable" delivery does not use the buffer.

Default
8192
Must be
0 < max_queued_changes
Environment variable
ANDROMEDA__NOTIFICATIONS__EVALUATION__MAX_QUEUED_CHANGES

notifications.evaluation.max_concurrent_changes​

positive integerrestart to apply

The most committed entity changes evaluated at once. Changes to one entity are evaluated one at a time in commit order; changes to different entities run side by side, each reading its entity and recording a notification per matched subscription, so they share the tenant's database pool with request handling.

Default
32
Must be
0 < max_concurrent_changes
Environment variable
ANDROMEDA__NOTIFICATIONS__EVALUATION__MAX_CONCURRENT_CHANGES

notifications.evaluation.drain_timeout​

durationrestart to apply

The longest a stopping tenant spends evaluating the committed changes it already holds for live delivery, at process shutdown or when the tenant is unloaded. Evaluation that is not finished by then is abandoned and the changes still waiting are dropped, logged and counted. At process shutdown the whole broker stops within server.graceful_drain_timeout plus this, 60 seconds by default, so give it the two together plus 10 seconds before your orchestrator kills it. "durable" delivery records notifications in the commit and is not affected.

Default
"30s"
Environment variable
ANDROMEDA__NOTIFICATIONS__EVALUATION__DRAIN_TIMEOUT

[notifications.periodic]​

How the periodic (timeInterval) notification drain waits.
[notifications.periodic]
max_poll_interval = "30s"

notifications.periodic.max_poll_interval​

non-zero durationrestart to apply

The longest the periodic notification drain sleeps while no subscription is due. The drain otherwise sleeps until the next subscription is due, so a change to the periodic subscriptions is noticed within this time; due notifications are sent on time either way.

Default
"30s"
Must be
0 < max_poll_interval
Environment variable
ANDROMEDA__NOTIFICATIONS__PERIODIC__MAX_POLL_INTERVAL