Configuration Reference
This page documents runtime-relevant configuration fields and defaults.
Topic Wire Format
- Topic wire subjects always use
.as separator. - Per-schema
topic.separatoris no longer used. - Token values are percent-encoded for reserved chars (
.,*,>,%) before writing to backend subjects.
See Topic Encoding for rules and examples.
application
| Setting | Default |
|---|---|
host | none |
port | none |
base_url | http://localhost |
static_files_path | /app/static |
homepage | public client and server links |
host
Bind address.
port
Bind port.
base_url
Used in generated CloudEvent source links.
static_files_path
Static asset root for homepage assets. The directory holds index.html, the
homepage, and the files it links: logo.png, which is also the PNG favicon,
and favicon.svg. Both icons are the documentation’s own. A custom directory
needs all three files.
homepage
The homepage puts the Aviso client card before the Aviso server card. Each card links to its documentation and GitHub repository. A separate HTTP API reference section opens this server’s Swagger UI.
All four fields are optional strings. Omitting the object or any field keeps the corresponding default:
| Field | Default |
|---|---|
client_documentation_url | https://sites.ecmwf.int/docs/aviso-client/main/ |
client_repository_url | https://github.com/ecmwf/aviso-client |
server_documentation_url | https://sites.ecmwf.int/docs/aviso-server/main/ |
server_repository_url | https://github.com/ecmwf/aviso-server |
Set these under application.homepage in YAML. Environment overrides take
priority over file values, using these exact keys:
AVISOSERVER_APPLICATION__HOMEPAGE__CLIENT_DOCUMENTATION_URL
AVISOSERVER_APPLICATION__HOMEPAGE__CLIENT_REPOSITORY_URL
AVISOSERVER_APPLICATION__HOMEPAGE__SERVER_DOCUMENTATION_URL
AVISOSERVER_APPLICATION__HOMEPAGE__SERVER_REPOSITORY_URL
Startup rejects URLs that cannot be parsed as absolute HTTP or HTTPS URLs with a host, or that contain a username or password. The error names the configuration field without printing its value. Links are HTML-escaped when rendered, including quotes and query-string ampersands.
logging
level
One of trace, debug, info, warn, error. Unknown values fall back to
info instead of failing startup. Used as the application-wide level when
RUST_LOG is unset.
format
Kept for compatibility; output is OTel-aligned JSON.
Runtime override via RUST_LOG
If the RUST_LOG environment variable is set, it takes priority over
logging.level and gives the operator full
EnvFilter directive syntax
for runtime triage without a code change. Examples:
RUST_LOG=info,aviso_server=debug
RUST_LOG=warn,aviso_server::auth=trace
RUST_LOG=info,aviso_server::sse=debug,actix_web=warn
A malformed RUST_LOG value is reported on stderr at startup and the server
falls back to logging.level. The most common parse failures are an empty
target before = (for example RUST_LOG==warn) and a non-level value after
= (for example RUST_LOG=info,aviso_server=verbose).
A missing comma like RUST_LOG=info aviso_server=debug does not trigger the
fallback. EnvFilter parses the whole string as a single target name with a
space, and the directive ends up matching nothing instead of failing loudly. If
a RUST_LOG value looks correct but no logs appear, double-check the commas
first.
RUST_LOG="" (empty string) is treated as if RUST_LOG were unset and falls
back to logging.level. Without this guard EnvFilter::try_new("") silently
succeeds with a filter that matches nothing and silences the entire process.
This is a real failure mode under deployment systems that export unset variables
as empty strings, such as the Kubernetes downward API or docker-compose’s
${VAR:-}.
When RUST_LOG is unset, the default filter combines logging.level with a
small set of mute directives so that framework internals do not flood
operational logs:
| Directive | Effect |
|---|---|
actix_web=warn | Caps Actix-web request lifecycle logs at warn (worker started, accepting, etc.). |
actix_server=warn | Caps Actix-server lifecycle logs at warn. |
async_nats=info | Caps the NATS client at info; trace/debug per-message chatter stays off. |
These mute directives are pinned by unit tests, only apply when RUST_LOG is
unset, and only apply when the directive’s level is more restrictive than
logging.level. With logging.level=warn or logging.level=error the
directives are skipped entirely so they never raise the per-target ceiling above
what the operator chose; with logging.level=info the two actix_*=warn
directives narrow framework chatter while async_nats=info is skipped (it would
be neutral); with logging.level=debug or logging.level=trace all three
directives apply. Setting RUST_LOG opts out of all of them and gives the
operator full directive control.
Push-based export via logging.otlp
Logs are always written to stdout as OTel-aligned JSON. With an otlp
block the server additionally pushes every log record to an OpenTelemetry
collector over OTLP, for clusters where log collection is push-based
instead of scraping container output.
enabled
Turns OTLP log export on. Startup fails when enabled without an endpoint.
endpoint
Collector endpoint. A missing scheme defaults to http://. For
protocol: http the OTLP path /v1/logs is appended when absent.
protocol
Transport. Collectors conventionally listen on 4317 for gRPC and 4318 for HTTP.
logging:
level: info
format: json
otlp:
enabled: true
endpoint: "http://otel-collector.observability.svc:4317"
protocol: grpc
Operational behavior:
- Export runs on a background batch thread with a bounded queue. A slow or unreachable collector never blocks request handling; overflow drops records from the export path only, and stdout remains complete.
- Export errors are reported by the SDK’s internal diagnostics on stdout,
so a broken collector connection is visible in
kubectl logs. - Export health is measurable on the Prometheus endpoint:
aviso_otlp_export_failures_totalcounts failed batch exports andaviso_otlp_suppressed_log_records_totalcounts records withheld by the redaction guard. Alert on a sustained non-zero rate of either. - Exported records carry the same request context as stdout records:
request_id,username,auth_realm,event_typeandtopic, taken from the request when the log event does not set them itself. Each key appears once, with the event’s own value when it has one. - The global filter (
logging.level/RUST_LOG) applies to both sinks, so the collector receives the same event stream as stdout. The export transport’s own targets (opentelemetry*,tonic,hyper,h2,tower,reqwest) are excluded from the export path to prevent feedback loops; they still appear on stdout. - Exported records carry the same resource identity as stdout records
(
service.name,service.version, andk8s.namespace.name/k8s.pod.namewhen the corresponding environment variables are set). - Redaction on the export path is stricter than stdout: record bodies get
the same pattern redaction, but a record carrying a sensitive attribute
key (
password,secret,token,authorization,api_key) or a URL value with embedded credentials is withheld from export entirely. The stdout copy of the same record keeps field-level[REDACTED]markers, so no information is lost to operators. - On shutdown the server flushes buffered records before exiting.
The endpoint can also be injected without a config file change via
environment overrides, for example
AVISOSERVER_LOGGING__OTLP__ENDPOINT=http://collector:4317.
auth
Authentication is optional. When disabled (default), all API endpoints are
publicly accessible only if schemas do not define stream auth rules. Startup
fails if global auth is disabled while a schema sets auth.required=true or
non-empty auth.read_roles/auth.write_roles.
When enabled:
- Admin endpoints always require a valid JWT and an admin role.
- Stream endpoints (
notify,watch,replay) enforce authentication only when the target schema hasauth.required: true. - Schema endpoints (
/api/v1/schema) are always public. - In
trusted_proxymode, Aviso validatesAuthorization: Bearer <jwt>locally withjwt_secret.
| Setting | Default |
|---|---|
enabled | false |
mode | "direct" |
auth_o_tron_url | "" |
jwt_secret | "" |
admin_roles | {} |
timeout_ms | 5000 |
enabled
Set to true to enable authentication.
mode
direct: forward credentials to auth-o-tron. trusted_proxy: validate
forwarded JWT locally.
auth_o_tron_url
auth-o-tron base URL. Required when enabled=true and mode=direct.
jwt_secret
Shared HMAC secret for JWT validation. Required when enabled=true. Not
exposed via /api/v1/schema endpoints and redacted when auth settings are
serialized or logged.
admin_roles
Realm-scoped roles for admin endpoints (/api/v1/admin/*). Must contain at
least one realm with non-empty roles when enabled=true.
timeout_ms
Timeout for auth-o-tron requests (milliseconds). Must be > 0.
Per-stream auth (notification_schema.<event_type>.auth)
| Setting | Default |
|---|---|
required | (none) |
read_roles | (none) |
write_roles | (none) |
plugins | (none) |
required
Must be explicitly set whenever an auth block is present. When true, the
stream requires authentication.
read_roles
Realm-scoped roles for read access (watch/replay). When omitted, any
authenticated user can read. Use ["*"] as the role list to grant realm-wide
access.
write_roles
Realm-scoped roles for write access (notify). When omitted, only users matching
global admin_roles can write. Use ["*"] as the role list to grant
realm-wide access.
plugins
Optional list of authorization plugins to run after role-based checks.
Currently supported: "ecpds" (requires --features ecpds build). On a build
without the required feature, startup fails with a clear error pointing at
the offending stream. (Silent skip would widen access.) Empty plugins: []
is rejected; omit the field instead. Plugins only run when auth.required
is true.
See Authentication for detailed setup, client usage, and error responses.
ecpds
Optional ECPDS destination authorization, available when built with
--features ecpds. Add "ecpds" to a stream’s auth.plugins list to check
destination access on watch and replay requests.
| Setting | Default |
|---|---|
username | none |
password | none |
servers | none |
match_key | none |
target_field | "name" |
cache_ttl_seconds | 300 |
max_entries | 10000 |
request_timeout_seconds | 30 |
connect_timeout_seconds | 5 |
partial_outage_policy | "strict" |
username
Service account username used for HTTP Basic Auth to ECPDS.
password
Service account password used for HTTP Basic Auth to ECPDS. It is redacted
in configuration debug output. The schema discovery API does not expose the
top-level ecpds settings.
servers
Use HTTPS to protect credentials and destination lookups. HTTP is accepted
only for local testing with 127.0.0.1, [::1], or localhost; other HTTP
addresses fail startup validation.
servers is a list of base URL strings, without query strings or fragments.
Path prefixes such as https://proxy.example/ecpds-api/ are supported. Aviso
appends /ecpds/v1/destination/list?id=<username> to each base URL.
match_key
Set match_key to an ordinary identifier such as destination, declared in
the schema with required: true. The name must not contain whitespace, /,
or NUL. When the schema defines a topic, include this field in
topic.key_order so delivery is filtered by the authorized destination.
Spatial identifiers cannot be match keys: PolygonHandler,
PointCloudHandler, and the field name polygon are not allowed. Spatial
matching does not enforce access to an exact destination value.
target_field
Selects a JSON field from each ECPDS destination record.
Records missing that field are skipped. To investigate missing destinations,
set RUST_LOG=info,aviso_ecpds=debug and look for
auth.ecpds.fetch.skipped_record events.
cache_ttl_seconds
How long to cache a user’s destination list before fetching it again. Use a whole number of seconds.
max_entries
Maximum number of users in the destination cache. Use a whole number. The cache uses TinyLFU eviction when it needs to make room.
request_timeout_seconds
Maximum time for the whole ECPDS request, from DNS lookup through reading the response body. Use a whole number of seconds.
connect_timeout_seconds
Maximum time to establish the connection, including TCP and TLS. This counts toward the total request timeout; it is not extra time. Use a whole number of seconds.
partial_outage_policy
Controls what happens when an ECPDS server is unavailable:
strict: every configured server must respond successfully. If any fails, the destination lookup fails with HTTP 503.any_success: combine destinations from the servers that respond successfully. The lookup fails if none succeeds.
In both modes, Aviso combines the returned destination lists. With
any_success, destinations known only to an unavailable server may be
missing. See Partial outage policy
for the trade-off.
See ECPDS Destination Authorization for setup and runtime behavior, and the ECPDS runbook for troubleshooting.
metrics
Optional Prometheus metrics endpoint. When enabled, a separate HTTP server
serves /metrics on an internal port for scraping by Prometheus/ServiceMonitor.
This keeps metrics isolated from the public API.
enabled
Enable the metrics endpoint.
host
Bind address for the metrics server. Defaults to loopback to avoid public exposure.
port
Required when enabled=true. Must differ from application.port.
Exposed metrics:
| Metric | Type |
|---|---|
aviso_build_info | gauge |
aviso_http_requests_total | counter |
aviso_http_request_duration_seconds | histogram |
aviso_http_requests_in_flight | gauge |
aviso_backend_operations_total | counter |
aviso_backend_operation_duration_seconds | histogram |
aviso_notifications_total | counter |
aviso_sse_connections_active | gauge |
aviso_sse_connections_total | counter |
aviso_sse_unique_users_active | gauge |
aviso_sse_events_sent_total | counter |
aviso_sse_stream_errors_total | counter |
aviso_sse_connection_duration_seconds | histogram |
aviso_auth_requests_total | counter |
aviso_build_info
Constant 1 with the server version as a label; join on it in dashboards to
annotate deploys.
aviso_http_requests_total
HTTP requests on the main server by matched route pattern (e.g.
/api/v1/schema/{event_type}). Reserved label values: unrouted requests (404
scans) collapse into route="unmatched", requests failing with a service-level
error (no route information available) record route="error", and non-standard
HTTP methods collapse into method="other". The label is named route (not
endpoint) to avoid colliding with the Prometheus Operator target label
endpoint.
aviso_http_request_duration_seconds
Request duration until response headers are ready. For the SSE routes
(/api/v1/watch, /api/v1/replay) this is stream setup latency, not
connection lifetime; see aviso_sse_connection_duration_seconds.
aviso_http_requests_in_flight
HTTP requests currently being processed, by method. Labelled by method only because the matched route pattern is not known until routing completes (after the request is already in flight). Distinguishes “slow because busy” from “slow because a downstream/backend stalled”.
aviso_backend_operations_total
Notification-backend operations at the trait boundary. operation ∈
{publish, get_batch, wipe_stream, wipe_all, delete_message}; outcome
∈ {ok, error}. subscribe_to_topic is excluded (its work happens lazily as
the stream is polled).
aviso_backend_operation_duration_seconds
Caller-observed backend operation latency (same labels as
aviso_backend_operations_total). This is the metric to watch when notification
throughput plateaus while pods are underused: it isolates backend
(NATS/JetStream) latency from app CPU.
aviso_notifications_total
Total notification requests. status ∈ {success, error, rejected};
requests failing before schema validation record event_type="unknown".
aviso_sse_connections_active
Currently active SSE connections. route ∈ {/api/v1/watch, /api/v1/replay}.
aviso_sse_connections_total
Total SSE connections opened.
aviso_sse_unique_users_active
Distinct users with active SSE connections.
aviso_sse_events_sent_total
Notification events delivered to SSE clients. Heartbeats, control events, and close frames are not counted.
aviso_sse_stream_errors_total
Error events emitted into SSE streams after the response started (typed stream
errors and notification rendering failures); these are invisible to
aviso_http_requests_total because the stream already returned 200.
aviso_sse_connection_duration_seconds
SSE connection lifetime, observed when the connection closes (buckets 1s-24h).
Long-lived open connections appear in aviso_sse_connections_active, not here,
until they close.
aviso_auth_requests_total
Authentication attempts. mode ∈ {direct, trusted_proxy}; outcome ∈
{success, unauthorized, forbidden, service_unavailable}.
The SSE and HTTP request metrics share a route label whose values are real
route patterns (e.g. /api/v1/watch), so a single dashboard route variable
spans both. Like the ECPDS counters below, the bounded label combinations of
aviso_auth_requests_total, aviso_notifications_total (including one series
per configured stream), and aviso_backend_operations_total /
aviso_backend_operation_duration_seconds (per active backend) are
pre-initialised at zero on startup so rate(...) > 0 alert rules evaluate
against existing series.
A binary built with --features ecpds registers the following five metrics. The
unlabelled counters and the gauge appear as Prometheus series at process
startup. The two labelled counters (access_decisions_total, fetch_total)
are pre-initialised at startup with every documented outcome value, so each
outcome label appears as a series at zero before any ECPDS traffic; this lets
alert rules of the form rate(metric{outcome="error"}[5m]) > 0 start evaluating
on a known-zero baseline rather than on a missing series.
| Metric | Type |
|---|---|
aviso_ecpds_cache_hits_total | counter |
aviso_ecpds_cache_misses_total | counter |
aviso_ecpds_cache_size | gauge |
aviso_ecpds_access_decisions_total | counter |
aviso_ecpds_fetch_total | counter |
aviso_ecpds_cache_hits_total
ECPDS destination cache hits (requests served from cache without an upstream call).
aviso_ecpds_cache_misses_total
ECPDS destination cache misses (requests not served from cache). Includes
coalesced waiters that did not trigger an upstream call themselves;
aviso_ecpds_fetch_total is the right metric for “actual upstream calls”.
aviso_ecpds_cache_size
Number of usernames in the ECPDS destination cache, sampled from moka after eviction passes. Expired entries are pruned by moka asynchronously, so this gauge can briefly include not-yet-pruned expired entries until the next pending-tasks run.
aviso_ecpds_access_decisions_total
Access decisions. outcome ∈ {allow, deny_destination,
deny_match_key_missing, unavailable, admin_bypass, error}.
aviso_ecpds_fetch_total
Upstream fetch outcomes (recorded once per access check whose request actually
ran the upstream call; coalesced waiters do not contribute). outcome ∈
{success, http_401, http_403, http_4xx, http_5xx, invalid_response,
unreachable}.
Process-level metrics (CPU, memory, open FDs) are automatically collected on Linux.
notification_backend
| Field | Type | Default | Notes |
|---|---|---|---|
kind | string | none | jetstream or in_memory. |
in_memory | object | optional | Used when kind = in_memory. |
jetstream | object | optional | Used when kind = jetstream. |
notification_backend.in_memory
| Field | Type | Default | Notes |
|---|---|---|---|
max_history_per_topic | usize | 1 | Retained messages per topic in memory. |
max_topics | usize | 10000 | Max tracked topics before LRU-style eviction. |
enable_metrics | bool | false | Enables extra internal metrics logs. |
See InMemory Backend for operational caveats.
notification_backend.jetstream
| Setting | Default |
|---|---|
nats_url | nats://localhost:4222 |
token | None |
timeout_seconds | 30 |
retry_attempts | 3 |
max_messages | None |
max_bytes | None |
retention_time | None |
storage_type | file |
replicas | None |
retention_policy | limits |
discard_policy | old |
max_reconnect_attempts | unlimited |
reconnect_delay_ms | 2000 |
publish_retry_attempts | 5 |
publish_retry_base_delay_ms | 150 |
nats_url
NATS connection URL.
token
Token auth; NATS_TOKEN env fallback.
timeout_seconds
NATS connection timeout for each startup connect attempt (> 0).
retry_attempts
Startup connect attempts before backend init fails (> 0).
max_messages
Stream message cap.
max_bytes
Stream size cap in bytes.
retention_time
Default stream max age (s, m, h, d, w; for example 30d).
storage_type
file or memory (parsed as typed enum at config load).
Omitting this setting requests file. Existing streams must use the requested
type: a mismatch fails stream setup before any mutable settings change. The
error
names the stream and its current and requested types. Aviso does not delete or
recreate streams, so messages remain intact. Use the current type or arrange a
separate migration.
replicas
Stream replicas.
retention_policy
limits/interest. workqueue fails startup because independent watch/replay
consumers are not supported.
discard_policy
old/new (parsed as typed enum at config load).
max_reconnect_attempts
Mapped to NATS max_reconnects; unset and 0 both mean unlimited. A positive
value makes the client give up permanently once exhausted.
Subscription creation uses a bounded retry loop: unset means five attempts,
0 means one attempt, and a positive value sets the attempt limit. Startup
connection attempts are controlled separately by retry_attempts.
reconnect_delay_ms
Reconnect delay and startup connect retry backoff (> 0).
publish_retry_attempts
Retry attempts for transient publish channel closed failures (> 0).
publish_retry_base_delay_ms
Base backoff in milliseconds for publish retries (> 0).
See JetStream Backend for detailed behavior.
notification_schema_strict
Controls how the server treats event_type values that are not declared in
notification_schema.
| Setting | Default |
|---|---|
notification_schema_strict | derived |
notification_schema_strict
When unset, the effective value is true if notification_schema is
non-empty, false otherwise. Set to true to force strict rejection even
with no schema (deny-all “drain” mode). Set to false to preserve the legacy
permissive generic fallback even with a declared schema; a startup warning is
emitted in that case.
In strict mode, POST /api/v1/notification, POST /api/v1/watch, and
POST /api/v1/replay reject any event_type not present in
notification_schema with 400 UNKNOWN_EVENT_TYPE.
The error body is:
{
"code": "UNKNOWN_EVENT_TYPE",
"error": "unknown_event_type",
"message": "unknown event type 'X'",
"configured_event_types": ["dissemination", "mars", "test_polygon"],
"request_id": "<uuid>"
}
configured_event_types is sorted for stable diffing in client tooling.
The same flag also bounds Prometheus / tracing label cardinality. Whenever
effective strict mode is off (either notification_schema_strict is
explicitly false, or it is unset with an empty/absent notification_schema
so the startup default resolves to non-strict), a request whose event_type
is not in the schema reaches the generic-fallback path and has its recorded
event_type label collapsed to the literal "generic" instead of being
persisted as user-controlled input.
notification_schema.<event_type>.payload
Schema-level payload contract for notify requests.
| Field | Type | Example | Notes |
|---|---|---|---|
required | bool | true | When true, /notification rejects requests without payload. |
Behavior details and edge cases are documented in Payload Contract.
notification_schema.<event_type>.max_historical_notifications
Optional positive integer overriding
watch_endpoint.max_historical_notifications
for this event type. Omit it to inherit the global cap (default 10000).
Zero and unlimited are rejected. This field sits outside storage_policy
and works with both backends. See Replay Limit
for an example and
Historical Replay Limits
for the wire behavior.
notification_schema.<event_type>.storage_policy
Optional per-schema storage settings validated at startup against selected backend capabilities.
| Setting | Example |
|---|---|
retention_time | 7d, 12h, 30m |
max_messages | 100000 |
max_size | 512Mi, 2G |
allow_duplicates | true |
compression | true |
retention_time
Duration literal (s, m, h, d, w).
max_messages
Must be > 0.
max_size
Size literal (K, Ki, M, Mi, G, Gi, T, Ti).
allow_duplicates
Backend support is capability-gated.
compression
Backend support is capability-gated.
Field behavior:
retention_timeoverrides backend-level retention for the schema stream.max_messagesoverrides backend-level message cap for the schema stream.max_sizeoverrides backend-level byte cap for the schema stream.allow_duplicates = falsemaps to one message per subject (latest kept);trueremoves this cap.compression = trueenables stream compression when backend supports it.
Startup behavior:
- Schema storage policies inherit the backend
retention_policy; there is no per-schema override.workqueuefails startup because it does not support independent watch/replay consumers. Existing streams are not migrated or deleted by this validation. - Invalid
retention_time/max_sizeformat fails startup. - Unsupported fields for selected backend fail startup.
- Validation happens before backend initialization.
- With
in_memory, allstorage_policyfields are currently unsupported (startup fails if provided).
Runtime application behavior:
- Aviso uses the configuration loaded at startup. Config edits require a restart or rollout to all replicas; editing the file alone does not change policy.
storage_policyis applied on stream create and reconciled for existing JetStream streams when those streams are accessed by Aviso. There is no all-stream sweep at startup or in the background.- Aviso-managed stream subject binding is also reconciled to the expected
<base>.>pattern. - Mutable fields (retention/limits/compression/duplicates/replicas) are updated when drift is detected.
- Compression applies to future file-storage writes at the block level. Changing it does not automatically recompress existing history.
- Deleting and recreating a stream loses its stored messages; it does not rewrite history. Aviso provides no automatic history migration.
Example:
notification_backend:
kind: jetstream
jetstream:
nats_url: "nats://localhost:4222"
publish_retry_attempts: 5
publish_retry_base_delay_ms: 150
notification_schema:
dissemination:
topic:
base: "diss"
key_order: ["destination", "target", "class", "expver", "domain", "date", "time", "stream", "step"]
storage_policy:
retention_time: "7d"
max_messages: 2000000
max_size: "10Gi"
allow_duplicates: true
compression: true
watch_endpoint
| Setting | Default |
|---|---|
sse_heartbeat_interval_sec | 30 |
connection_max_duration_sec | 3600 |
replay_batch_size | 100 |
max_historical_notifications | 10000 |
replay_batch_delay_ms | 100 |
concurrent_notification_processing | 15 |
sse_heartbeat_interval_sec
SSE heartbeat period.
connection_max_duration_sec
Maximum live watch duration.
replay_batch_size
Historical backend fetch batch size, independent of the request-wide delivery cap. Filtering can leave a batch with no notifications to deliver; replay keeps advancing through history.
max_historical_notifications
Maximum historical notifications delivered per replay or replaying watch
request, across all batches and after identifier constraints, spatial filters
and successful CloudEvent rendering. Both backends enforce the same cap.
Live-only watches are unaffected. A schema can override this default with
notification_schema.<event_type>.max_historical_notifications, outside
storage_policy. Omitting the schema field inherits the global value.
The value must be a positive integer; zero and unlimited are rejected. The
server emits notification_replay_limit_reached only when it finds a renderable
notification beyond the cap. Exactly filling the quota is not truncation.
A truncated request closes without replay_completed or a transition to live
delivery. See
Historical Replay Limits.
replay_batch_delay_ms
Delay between historical replay batches.
concurrent_notification_processing
Live stream CloudEvent conversion concurrency.
Custom config file path
Set AVISOSERVER_CONFIG_FILE to use a specific config file instead of the
default search cascade:
AVISOSERVER_CONFIG_FILE=/path/to/config.yaml cargo run
When set, only this file is loaded as a file source (startup fails if it does
not exist). The default locations (./configuration/config.yaml,
/etc/aviso_server/config.yaml, $HOME/.aviso_server/config.yaml) are
skipped. AVISOSERVER_* field-level overrides still apply on top.
Environment override examples
AVISOSERVER_APPLICATION__HOST=0.0.0.0
AVISOSERVER_APPLICATION__PORT=8000
AVISOSERVER_NOTIFICATION_BACKEND__KIND=jetstream
AVISOSERVER_NOTIFICATION_BACKEND__JETSTREAM__NATS_URL=nats://localhost:4222
AVISOSERVER_NOTIFICATION_BACKEND__JETSTREAM__TOKEN=secret
AVISOSERVER_WATCH_ENDPOINT__REPLAY_BATCH_SIZE=200
AVISOSERVER_AUTH__ENABLED=true
AVISOSERVER_AUTH__JWT_SECRET=secret
AVISOSERVER_METRICS__ENABLED=true
AVISOSERVER_METRICS__PORT=9090