Skip to content

How it works

modalities ──► load balancer ──► node 1 ─┐ ┌─► PACS
(VIP, TCP 104) ► node 2 ─┼─ C-STORE ─┼─► AI service
(or DICOM TLS) ► node N ─┘ (or TLS) └─► archive
▲ heartbeats, configuration, history
▼
central service(s) ── SQL Server or PostgreSQL
(web console, HTTPS)

Nodes do the work. Each one listens for DICOM (and, when you turn them on, DICOMweb and HL7), decides where every instance goes, keeps it on its own disk until each destination has it, and sends it on. A node needs to know only the central service’s address and an enrollment key; it receives everything else from the central service.

The central service holds the configuration, serves the web console, collects the history of every instance and delivery, raises alerts and coordinates the nodes. Nodes send it a heartbeat every couple of seconds; a configuration change reaches every node within about two seconds, without a restart.

Routing does not depend on the central service being up. Nodes keep routing with the configuration they have, and send their history once they can reach it again. You can run several central servers on one database, all active, for redundancy or one per region.

Three things decide where an instance goes:

  • A source describes who sends: calling AE titles (wildcards allowed), the AE title they call, their IP addresses and the port they arrive on. It can also require header values (only Modality = CT, say), edit what it receives, and set which transfer syntaxes it accepts.
  • A destination is where instances go: a DICOM system (host, port, called AE title), a DICOMweb service, or a group of destinations that fail over or share the load. A destination can edit, convert or de-identify what it sends, follow a schedule, and limit its bandwidth.
  • A route connects a source to one or more destinations. Routes are checked top to bottom and the first that matches wins. A route can also hold instances until the study is complete, set a priority, check the patient against the order, and fetch the patient’s prior studies.

When a sender connects, the node finds the routes whose source accepts it (its AE titles, address and port). Senders no route accepts are refused at once, and show up on the monitoring page as turned away. Each instance is then checked against those routes’ sources’ header conditions, and queued for the first matching route’s destinations.

  1. The node receives it and checks it against the routes. The source’s tag edits and script run.
  2. The instance is written to the node’s disk once and queued for each destination. Destinations do not wait for each other: a PACS that is down does not hold up the archive.
  3. Each destination’s queue sends in priority order, converting the transfer syntax if the destination needs another, and applying its own edits or de-identification.
  4. A destination that cannot be reached is retried with growing pauses; the instances wait on disk. An instance a destination refuses for good becomes a dead letter, which you can send again after fixing the cause.
  5. Every step is recorded in the history: who sent what, where it went, in which transfer syntax, and when.

Everything is set and watched in the web console of the central service:

  • Monitoring: every transfer in progress, live.
  • History: every instance received and every delivery, searchable; dead letters, quarantine, prior-study requests, AI jobs, the reconciliation queue and HL7 messages.
  • Nodes: each node’s state, queues and problems; drain and resume.
  • Alerts, Reports and the Audit log.
  • Configuration: sources, destinations, routes and every setting, with a route tester and a full version history.