Parallelizing an Import Without Corrupting References

Editorial illustration in kirigami-cutout style depicting three ordered lanes of resource types running in parallel with reference arrows resolving cleanly forward, never backward

Parallelizing a FHIR import is the single biggest lever for cutting duration. Running eight workers instead of one drops the wall clock by a factor of four to seven. But naïve parallelization corrupts references — worker A writes an Observation before worker B writes the Patient it references, and the reference lands dangling. Handling that ordering constraint is the specific discipline of parallel FHIR imports. The site's Bulk import time estimator factors parallelism into its output. For the wider FHIR framing, the FHIR field guide here on the site has more.

The Reference Ordering Problem

  • Observation references Patient
  • Patient must be written before Observation, or the reference is broken
  • If workers write in parallel without coordination, the order is arbitrary

Naïve parallelism produces broken references.

For the base ETA framing, predicting how long a FHIR data import will take is the entry.

Solution One: Type-Ordered Passes

  • Pass 1: write all Patients in parallel
  • Pass 2: write all Practitioners in parallel
  • Pass 3: write all Observations, MedicationRequests, etc. in parallel

Each pass finishes before the next starts. Within a pass, workers are safe because entries reference resources from prior passes.

Simple, correct, slightly slower than fully parallel.

Solution Two: Reference Batches

Group resources by their reference dependencies. All entries in a batch reference only resources from earlier batches or the current batch.

More complex to compute up front, more efficient to run.

For the driver-analysis side, the four dominant drivers of import duration is the entry.

Solution Three: Lax-Integrity Server Plus Verification Pass

If the server tolerates dangling references (many do by default), write everything in parallel and verify integrity after.

Fastest during the write. Adds a verification pass afterward. Right when the verification pass fits in the schedule.

The Batch Size Question

Each worker processes a batch of resources per transaction. Bigger batches = fewer round trips. Smaller batches = smaller retries.

  • 100 resources per batch — reasonable default for most servers
  • 500 — some servers benefit
  • 5000 — usually too large

Tune per server.

The Worker Count

Server sustained throughput divided by per-worker throughput = optimal worker count. Beyond that, adding workers produces contention, not throughput.

For a server that sustains 1000 writes/second and per-worker throughput of 200 writes/second, five workers is optimal. Eight workers produces contention and worse throughput than five.

Measure both. Do not guess.

The urn:uuid: Case

Transaction Bundles use urn:uuid: for cross-entry references. Parallel workers writing Bundles that reference each other's URNs is a mess.

Rule: URNs are Bundle-local. Do not use urn:uuid: for cross-batch references. Use real ids or Reference.identifier.

Failure Isolation

  • One worker fails — other workers keep going
  • One batch fails — retry the batch on a different worker
  • Whole import fails — recover from the failure point

Design for failure per batch, not per import. For the recovery side, recovering from a failed import without starting over is the entry.

Read-After-Write Contention

Some parallel imports read the just-written data during subsequent writes. If the server has read-after-write inconsistency, you get flakes.

  • Wait for write confirmation before dependent read
  • Use strongly-consistent read APIs
  • Retry with backoff on read-not-found

Rate Limiting Coordination

Parallel workers can collectively exceed the server's rate limit even if each worker is under it. Coordinate the fleet's request rate, not just per-worker rate.

Simplest coordination: single token bucket in a small shared cache. Workers acquire tokens before each request.

The Metrics Question

Every worker should emit:

  • Requests per second
  • Success rate
  • Retry rate
  • Batch size

Aggregate across workers to get the fleet's actual throughput. For monitoring, monitoring an in-flight import for the numbers that matter is the entry.

The Short Version

Type-order passes, reference batches, or lax + verification. Batch size matters. Worker count matches sustained throughput. Coordinate rate limits across workers. Design for per-batch failure. That is parallel FHIR import that survives.

Kirigami-cutout diagram of a parallel import with type-ordered passes producing safe references, drawn as clean paper-cutout shapes with deep-blue accents on ivory

Sources

  • HTML - HTML, HL7 FHIR - References and how they work

Emily Tran

HIM specialist from San Diego. Covers clinical document exchange, C-CDA, and the long tail of EHR migration projects.