Dcm4chee: PACS Synchronization via Dicom Forwarding
Suppose you need to synchronize a secondary PACS with that of a primary one running dcm4chee. Perhaps this is part of a simple fault-tolerant networking solution with the secondary PACS acting as a hot-backup, or perhaps you have some other goal in mind.
The good news is that in dcm4chee synchronisation via DICOM forwarding is actually rather easy as dcm4chee comes with three different forwarding services, each tailored for slightly distinct use cases. The services are:
- ForwardByQuery – this service will forward series to a new AET based on an sql-like query parameter. This is useful for say, performing one-time PACS migrations. It can also be used to forward new series as they come in. This service is configured via the jmx-console. I’m not sure where the official docs are.
- Forward – This is a basic forwarding service which allows forwarding rules based on incoming AET. It allows for multiple forwarding rules, and delayed forwarding based on time of day. This service is configured via the jmx-console. The official docs are here.
- Forward2 – This service does all that “Foward” does and more, allowing the specification of much more detailed forwarding rules (ie: by modality or referring physician). While more powerful, the rub is that it requires more knowledge to configure. It is configured via a config file located in $DCM4CHEE/server/default/conf/dcm4chee-ae, refenced from the jmx-console. The official docs are here.
Here, I’ll be focusing on the Forward service, befitting a setup where there is no need for the more sophisticated forwarding rules offered by Forward2. This would be sufficient for a simple primary PACS + hot backup setup, or perhaps for setting up a system with multiple ‘feeder’ PACSs with all studies forwarded to a central ‘master’ node.
Finally, ForwardByQuery strikes me as a potentially interesenting alternative to Forward. However, because it works by polling the db via an sql query (as opposed to ‘listening’), it strikes me as potentially less performant, and trickier to get right for real-time forwarding (one can imagine making mistakes in the query such that some studies get sent more than once, or not at all). However, ForwardByQuery does strike me as well suited for performing initial data migration to a secondary PACS (if say we were to introduce a backup to a preexisting system and wanted a complete or partial replication of the data).
PACS synchronization via dcm4chee’s forward service
Dcm4chee’s Forward service is the simplest way to forward series upon receipt from a primary dcm4chee instance. The setup is as follows:
- The primary and secondary PACS need to have distinct AETs, this is a dcm4chee requirement due to dcm4chee assuming that the AET of an AE is unique (and not say, modulo IP / port). The easiest and safest way to change the AET of a dcm4chee instance from it’s default of “DCM4CHEE” is via the jmx-console (at http://the_pacs_url/jmx-consle) by invoking the updateAETitle function within the AE service bean. Let’s suppose we’ve done this such that our primary and secondary PACS are named PACS1 and PACS2, respectively.
- In the primary PACS, define a new AE via the web-gui (http://the_primary_pacs_url/dcm4chee-web3) for the secondary PACS. The AET of the new AE needs to correspond to that of the backup PACS you set in the previous step, ie: “PACS2.”
- In the primary PACS, set the forwarding rule by going to the Forward service bean in the jmx-console and simply adding a line to the top of the “ForwardingRules” field with syntax described in the jmx-console. A few example rules are as follows:
Adding the above line simply forwards all new series, to the backup PACS, as they come in.
This rule schedules forwarding of all new series to the backup AET, but delays forwarding so as not to occur between the hours of 8am and 8pm (presumably peak business hours).
This rule forwards all new series coming from AETs INCOMING1 and INCOMING2, to two different backup instances, but delays forwarding so as not to occur between the hours of 8am and 8pm (presumably peak business hours).
A few random gotchas
Here are a few gotchas that come to mind, in no particular order:
- Called AET title not found. Ie: Backup aet title is misconfigured either in primary, backup or both. This title must coincide with the backup instance’s aet and be different from that of the primary instance’s aet (by default, both are set to “DCM4CHEE,” as described above, this is remedied by calling the updateAETitle from the AE bean in the jmx-console). The quickest way to debug this is to use the ping / echo service when setting up the backup AE in the primary PACS via it’s jmx-console. The echo test should pass.
- Your forwards throw timeout errors “ava.lang.IllegalStateException: Error writing. Current state is: Sta 1 – Idle” — check your DIMSETimeout parameter in the service=QueryRetrieveScp and set it to 0 (no timeout), your network is likely too slow for the one of the files in the set.
- Primary PACS accepts studies without patient name but backup does not. Result is that synchronization attempts will fail to write on the backup. Remedy: update the config of the backup PACS via it’s jmx-console to accept studies without patient name (assuming you want your system to tolerate this).
- AETs seem to be setup correctly for primary and backup, but dicom echo still fails on one end or the other. Remedy: Likely you have incorrect or unnecessary user / pass settings specified in the AE definitions table on one or both boxes. This might have happened due to your browser annoyingly and mistakingly autofilling user / pass data in the AE definition form (happened to me on chrome). In a default dcm4chee install, there should be no user / pass data in the AE definition, and these echos may fail if said data is present on one instance or the other.
Note: I am running dcm4chee v2.18.1.