Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration Reference

This page documents runtime-relevant configuration fields and defaults.

Topic Wire Format

  • Topic wire subjects always use . as separator.
  • Per-schema topic.separator is no longer used.
  • Token values are percent-encoded for reserved chars (., *, >, %) before writing to backend subjects.

See Topic Encoding for rules and examples.

application

SettingDefault
hostnone
portnone
base_urlhttp://localhost
static_files_path/app/static
homepagepublic client and server links
host Default: none · Type: string

Bind address.

port Default: none · Type: u16

Bind port.

base_url Default: http://localhost · Type: string

Used in generated CloudEvent source links.

static_files_path Default: /app/static · Type: string

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 Default: public project links · Type: object

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:

FieldDefault
client_documentation_urlhttps://sites.ecmwf.int/docs/aviso-client/main/
client_repository_urlhttps://github.com/ecmwf/aviso-client
server_documentation_urlhttps://sites.ecmwf.int/docs/aviso-server/main/
server_repository_urlhttps://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

SettingDefault
levelinfo
formatimplementation default
level Default: info · Type: string

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 Default: implementation default · Type: string

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:

DirectiveEffect
actix_web=warnCaps Actix-web request lifecycle logs at warn (worker started, accepting, etc.).
actix_server=warnCaps Actix-server lifecycle logs at warn.
async_nats=infoCaps 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.

SettingDefault
enabledfalse
endpointnone
protocol"grpc"
enabled Default: false · Type: bool

Turns OTLP log export on. Startup fails when enabled without an endpoint.

endpoint Default: none · Type: string

Collector endpoint. A missing scheme defaults to http://. For protocol: http the OTLP path /v1/logs is appended when absent.

protocol Default: "grpc" · Type: "grpc"|"http"

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_total counts failed batch exports and aviso_otlp_suppressed_log_records_total counts 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_type and topic, 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, and k8s.namespace.name / k8s.pod.name when 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 has auth.required: true.
  • Schema endpoints (/api/v1/schema) are always public.
  • In trusted_proxy mode, Aviso validates Authorization: Bearer <jwt> locally with jwt_secret.
SettingDefault
enabledfalse
mode"direct"
auth_o_tron_url""
jwt_secret""
admin_roles{}
timeout_ms5000
enabled Default: false · Type: bool

Set to true to enable authentication.

mode Default: "direct" · Type: "direct"|"trusted_proxy"

direct: forward credentials to auth-o-tron. trusted_proxy: validate forwarded JWT locally.

auth_o_tron_url Default: "" · Type: string

auth-o-tron base URL. Required when enabled=true and mode=direct.

jwt_secret Default: "" · Type: string

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 Default: {} · Type: map<string, string[]>

Realm-scoped roles for admin endpoints (/api/v1/admin/*). Must contain at least one realm with non-empty roles when enabled=true.

timeout_ms Default: 5000 · Type: u64

Timeout for auth-o-tron requests (milliseconds). Must be > 0.

Per-stream auth (notification_schema.<event_type>.auth)

SettingDefault
required(none)
read_roles(none)
write_roles(none)
plugins(none)
required Default: (none) · Type: bool

Must be explicitly set whenever an auth block is present. When true, the stream requires authentication.

read_roles Default: (none) · Type: map<string, string[]>

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 Default: (none) · Type: map<string, string[]>

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 Default: (none) · Type: string[]

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.

username Default: none · Type: nonempty string

Service account username used for HTTP Basic Auth to ECPDS.

password Default: none · Type: nonempty string

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 Default: none · Type: list of URL strings

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 Default: none · Type: string

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 Default: "name" · Type: string

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 Default: 300 · Unit: seconds · Minimum: 1

How long to cache a user’s destination list before fetching it again. Use a whole number of seconds.

max_entries Default: 10000 · Unit: users · Minimum: 1

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 Default: 30 · Unit: seconds · Minimum: 1

Maximum time for the whole ECPDS request, from DNS lookup through reading the response body. Use a whole number of seconds.

connect_timeout_seconds Default: 5 · Unit: seconds · Minimum: 1

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 Default: "strict" · Values: "strict", "any_success"

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.

SettingDefault
enabledfalse
host"127.0.0.1"
portnone
enabled Default: false · Type: bool

Enable the metrics endpoint.

host Default: "127.0.0.1" · Type: string

Bind address for the metrics server. Defaults to loopback to avoid public exposure.

port Default: none · Type: u16

Required when enabled=true. Must differ from application.port.

Exposed metrics:

aviso_build_info Type: gauge · Labels: version

Constant 1 with the server version as a label; join on it in dashboards to annotate deploys.

aviso_http_requests_total Type: counter · Labels: route, method, status_code

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 Type: histogram · Labels: route, method

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 Type: gauge · Labels: method

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 Type: counter · Labels: backend, operation, outcome

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 Type: histogram · Labels: backend, operation, outcome

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 Type: counter · Labels: event_type, status

Total notification requests. status ∈ {success, error, rejected}; requests failing before schema validation record event_type="unknown".

aviso_sse_connections_active Type: gauge · Labels: route, event_type

Currently active SSE connections. route ∈ {/api/v1/watch, /api/v1/replay}.

aviso_sse_connections_total Type: counter · Labels: route, event_type

Total SSE connections opened.

aviso_sse_unique_users_active Type: gauge · Labels: route

Distinct users with active SSE connections.

aviso_sse_events_sent_total Type: counter · Labels: route, event_type

Notification events delivered to SSE clients. Heartbeats, control events, and close frames are not counted.

aviso_sse_stream_errors_total Type: counter · Labels: route, event_type

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 Type: histogram · Labels: route

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 Type: counter · Labels: mode, outcome

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.

aviso_ecpds_cache_hits_total Type: counter · Labels: (none)

ECPDS destination cache hits (requests served from cache without an upstream call).

aviso_ecpds_cache_misses_total Type: counter · Labels: (none)

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 Type: gauge · Labels: (none)

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 Type: counter · Labels: outcome

Access decisions. outcome ∈ {allow, deny_destination, deny_match_key_missing, unavailable, admin_bypass, error}.

aviso_ecpds_fetch_total Type: counter · Labels: outcome

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

FieldTypeDefaultNotes
kindstringnonejetstream or in_memory.
in_memoryobjectoptionalUsed when kind = in_memory.
jetstreamobjectoptionalUsed when kind = jetstream.

notification_backend.in_memory

FieldTypeDefaultNotes
max_history_per_topicusize1Retained messages per topic in memory.
max_topicsusize10000Max tracked topics before LRU-style eviction.
enable_metricsboolfalseEnables extra internal metrics logs.

See InMemory Backend for operational caveats.

notification_backend.jetstream

nats_url Default: nats://localhost:4222 · Type: string

NATS connection URL.

token Default: None · Type: string?

Token auth; NATS_TOKEN env fallback.

timeout_seconds Default: 30 · Type: u64?

NATS connection timeout for each startup connect attempt (> 0).

retry_attempts Default: 3 · Type: u32?

Startup connect attempts before backend init fails (> 0).

max_messages Default: None · Type: i64?

Stream message cap.

max_bytes Default: None · Type: i64?

Stream size cap in bytes.

retention_time Default: None · Type: string?

Default stream max age (s, m, h, d, w; for example 30d).

storage_type Default: file · Type: string?

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 Default: None · Type: usize?

Stream replicas.

retention_policy Default: limits · Type: string?

limits/interest. workqueue fails startup because independent watch/replay consumers are not supported.

discard_policy Default: old · Type: string?

old/new (parsed as typed enum at config load).

max_reconnect_attempts Default: unlimited · Type: u32?

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 Default: 2000 · Type: u64?

Reconnect delay and startup connect retry backoff (> 0).

publish_retry_attempts Default: 5 · Type: u32?

Retry attempts for transient publish channel closed failures (> 0).

publish_retry_base_delay_ms Default: 150 · Type: u64?

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.

SettingDefault
notification_schema_strictderived
notification_schema_strict Default: derived · Type: bool?

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.

FieldTypeExampleNotes
requiredbooltrueWhen 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.

SettingExample
retention_time7d, 12h, 30m
max_messages100000
max_size512Mi, 2G
allow_duplicatestrue
compressiontrue
retention_time Example: 7d, 12h, 30m · Type: string

Duration literal (s, m, h, d, w).

max_messages Example: 100000 · Type: integer

Must be > 0.

max_size Example: 512Mi, 2G · Type: string

Size literal (K, Ki, M, Mi, G, Gi, T, Ti).

allow_duplicates Example: true · Type: bool

Backend support is capability-gated.

compression Example: true · Type: bool

Backend support is capability-gated.

Field behavior:

  • retention_time overrides backend-level retention for the schema stream.
  • max_messages overrides backend-level message cap for the schema stream.
  • max_size overrides backend-level byte cap for the schema stream.
  • allow_duplicates = false maps to one message per subject (latest kept); true removes this cap.
  • compression = true enables stream compression when backend supports it.

Startup behavior:

  • Schema storage policies inherit the backend retention_policy; there is no per-schema override. workqueue fails startup because it does not support independent watch/replay consumers. Existing streams are not migrated or deleted by this validation.
  • Invalid retention_time/max_size format fails startup.
  • Unsupported fields for selected backend fail startup.
  • Validation happens before backend initialization.
  • With in_memory, all storage_policy fields 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_policy is 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

sse_heartbeat_interval_sec Default: 30 · Type: u64

SSE heartbeat period.

connection_max_duration_sec Default: 3600 · Type: u64

Maximum live watch duration.

replay_batch_size Default: 100 · Type: usize

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 Default: 10000 · Type: usize

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 Default: 100 · Type: u64

Delay between historical replay batches.

concurrent_notification_processing Default: 15 · Type: usize

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