Skip to content

kastoria-eventnotification

An event notification publisher that follows the DICOMProcessed Changelog and publishes one Notification Event per study version to a queue. It is a one-shot image with no listening port: one invocation is one Execution, which becomes a Run by taking the Run Lease, publishes until it has caught up with the Changelog, and then exits. A deployment starts it on a schedule.

The events it publishes are described in Ingestion Manifest.

Runtime details

Property Value
Runtime base image kastoria-core (final stage), itself node:24-alpine
Exposed port none (CLI, runs to completion)
Container user node (non-root)
Entrypoint node --import ./event-notification/src/instrumentation.js ./event-notification/bin/cli.js
Health check none (not a long-running service)
Stop signal SIGTERM (the Run takes no new work, finishes what is in flight and exits normally)

Exit codes:

0 when the Lease was taken and the Run ended without a failed publish, including a Run stopped by SIGTERM. Also 0 when another Execution holds the Lease (the no-op tick).

Non-zero exits occur when:

  1. A Run stopped on an event it could not publish. That event is held, and the next Run publishes it again.
  2. A failure happened before the Lease was reached — configuration, storage initialization, or building the queue writer (for example, a missing or invalid queueWriter section).
  3. A bad input argument is provided.
  4. A second SIGTERM is received.
  5. Taking the Lease or reading the Changelog failed.

A failure while closing storage or flushing telemetry after the Run does not change the exit code.

node_modules for npm/npx are stripped from the runtime image.

OCI labels

Label Value
org.opencontainers.image.title Event Notification
org.opencontainers.image.description Publishes Notification Events for Kastoria Health
org.opencontainers.image.licenses Proprietary
org.opencontainers.image.url https://github.com/merkalis-io/kastoria-health
org.opencontainers.image.documentation https://github.com/merkalis-io/kastoria-health
io.kastoria.health-endpoint (empty — no health endpoint)

The org.opencontainers.image.version, org.opencontainers.image.revision, org.opencontainers.image.created, org.opencontainers.image.source, io.kastoria.base-image, and io.kastoria.service labels are injected at build time by the CI/CD pipeline.

Pull and verify

Promoted images are published to the Distribution Registry under the customer namespace:

docker pull acrmerkalisdist0c66.azurecr.io/<customer>/kastoria-eventnotification:<release-tag>
notation verify acrmerkalisdist0c66.azurecr.io/<customer>/kastoria-eventnotification:<release-tag>

See the Distribution Registry guide for authentication and trust setup.

Environment variables

Variable Secret Required Default Description
NODE_ENV No No production Environment; startup fails if unset.
KASTORIA_CONFIG_JSON[1][2] Yes one of these — Storage configuration as an inline JSON string.
KASTORIA_CONFIG_FILE[1][2] No one of these — Path to a storage configuration JSON file.
EVENT_NOTIFICATION_PUBLISH_CONCURRENCY No No 16 How many Notification Events a Run has in flight at once.
EVENT_NOTIFICATION_VISIBILITY_DELAY_MS No No 5000 How far short of NOW a Changelog read stops.
EVENT_NOTIFICATION_BATCH_SIZE No No 100 Entries one bounded Changelog read asks for.
AZURE_CLIENT_ID[3] No No — Client id of the user-assigned managed identity used to reach Azure storage.
OTEL_ENABLED[4] No No false Set to true to enable OpenTelemetry export.
OTEL_EXPORTER_OTLP_ENDPOINT[4] No No — OTLP collector endpoint, e.g. http://otel-gateway:4317.
OTEL_DEBUG[4] No No — Set to true for verbose OTel diagnostic logging.

The EVENT_NOTIFICATION_* values must be positive integers; any other value fails at startup.

The CLI subcommand (publish) is passed at run time.

Deploying to an Azure Container Apps Environment

[1] At least one of KASTORIA_CONFIG_JSON / KASTORIA_CONFIG_FILE is required for storage initialization. If both are set the value of KASTORIA_CONFIG_JSON is used. See Configuration for the document's contents.

[2] The configuration must include a queueWriter section naming the queue to publish to. With the Azure Storage Queue module the writer authenticates with a managed identity, so the section carries no credential:

"queueWriter": {
  "type": "azure-storage-queue",
  "configuration": {
    "accountName": "<queue storage account name>",
    "managedIdentityClientId": "<queue publisher identity client id>",
    "queueName": "kastoria-events",
    "messageEncoding": "text"
  }
}

messageEncoding is text (the JSON as-is) or base64 (the JSON's UTF-8 bytes, Base64-encoded). The queue is not created unless createQueueIfMissing is true; a missing queue otherwise fails the Run. The identity needs the Storage Queue Data Message Sender role on the queue's storage account; the queue module creates one, umi-<base_name>-queue-publisher, and grants it that role.

[3] AZURE_CLIENT_ID selects the storage identity, not the queue publisher. The container reads the Changelog from storage and publishes to the queue, so it carries two user-assigned identities: the storage identity (named by AZURE_CLIENT_ID) and the queue publisher (named by managedIdentityClientId in the queueWriter section). With the compute module, attach them through user_managed_storage_app and user_managed_queue_app.

[4] If OTEL_ENABLED is not explicitly set to true, OpenTelemetry metric/trace/logging is disabled.

Job configuration

The image is meant to run as a batch job that is setup to be run on a regular schedele. There is no long-running process to keep alive; the deployment is responsible for starting execution on a cadence. The following launch arguments should be passed into the container

["publish"]

To details on setting up the execution cadence and launch arguments in a deployed environment, see the jobs configuration documentation for the appropriate Terrform/OpenTofu compute module.

Available versions

  • v0.10.0
  • v0.9.1 — deprecated for security reasons (CVE-2026-101916); use v0.10.0