Skip to main content

Fire Arrow Server 1.16.0

· 4 min read

Fire Arrow Server 1.16.0 has been released.

  • (feature) CarePlans now carry a materialized-at-version marker, so a client can tell when the server has finished creating Tasks for its latest update without making a synchronous call
  • (bugfix) A scheduled activity's own Timing.repeat.duration now sets how long the resulting Task stays actionable, instead of always using the server-configured validity period

Knowing When Task Materialization Has Caught Up

When a CarePlan is subscribed to due events, the server materializes Task resources from the plan's scheduled activities. When a client then updates that CarePlan, the server re-materializes the affected Tasks in the background. Before 1.16.0 there was no low-cost way for a client to know when that background work had finished for a particular update: it either had to use the synchronous CarePlan/$subscribe-due-events path or repeatedly query Task and guess whether the new set was complete.

Starting with 1.16.0, once materialization for a CarePlan completes, the server records the CarePlan version it materialized in the CarePlan's meta:

https://firearrow.io/fhir/StructureDefinition/materialized-at-version

The value is a valueInteger holding the meta.versionId that was materialized. A client that updates a CarePlan can poll GET /CarePlan/{id} and wait until meta.extension[materialized-at-version] reaches the version it wrote; at that point the Tasks for that update are available and can be queried with Task?based-on=CarePlan/{id}. This replaces fixed sleeps or open-ended polling of the Task endpoint with a definite signal.

This marker is server-managed bookkeeping on meta, not clinical content in the CarePlan body. Writing it does not trigger another round of re-materialization — the server only re-materializes when an activity, a contained resource, or the plan period changes. Because the marker lives on meta, a CarePlan that participates in server-side scheduling gains one additional server-written version each time it is materialized; clients that track CarePlan version history will see these server-generated updates.

The synchronous renewal path — CarePlan/$subscribe-due-events with _synchronous=true for a CarePlan that is already subscribed — uses the same marker internally. It waits for in-flight materialization to catch up with the current CarePlan version before returning the Task set, so a synchronous renewal reflects the client's latest update rather than a partially materialized state. If materialization does not catch up within the wait window (10 seconds), the server returns the Tasks it has on a best-effort basis; any remaining Tasks still arrive through the usual asynchronous subscription notifications. No configuration change is required.

Bug Fixes

Task validity ignored the activity's Timing.repeat.duration

Each materialized Task carries a restriction.period.end that marks when it stops being actionable, after which the expiry sweeper moves it to a terminal status. When a scheduled activity declared its own length through Timing.repeat.duration — for example a MedicationRequest whose dosageInstruction.timing.repeat specifies duration = 18, durationUnit = h — the server extracted that duration but did not use it. It computed restriction.period.end purely from the server-configured validity (default-validity-period or the matching task-validity-periods tier), so an activity meant to stay actionable for 18 hours instead expired according to the configured window.

Starting with 1.16.0, when a scheduled activity's Timing.repeat.duration is present, that duration determines the Task's actionable window: restriction.period.end is set to the occurrence's due time plus the declared duration. The activity's own duration takes full precedence over the server-configured validity period — it replaces that window rather than merely capping it, so it can make the window either shorter or longer than the configured default. Activities that do not specify a Timing.repeat.duration are unchanged: their validity is still taken from default-validity-period and task-validity-periods as before.

This change applies to the repeating-schedule materialization path. Explicit one-off events, and activities backed by an Appointment, Task, or ServiceRequest that already carry their own end time, are unaffected. No configuration change is required.