Concurrent OTA and Local Service Updates: Give One Actor Ownership of Installation

Route OTA and local service requests through one admission owner, and keep ownership until the actual installation outcome is reconciled. A client timeout, expired management lease or closed technician window does not establish that the installer has stopped. Letting a second actor take over on that assumption creates ambiguous writes and misleading completion reports.

The concrete implementation example is the RAUC 1.14 D-Bus service. The surrounding broker and ownership record below are an original application design, not features automatically supplied by RAUC. No daemon calls or concurrent installations were executed. Other installers and downstream patches require their own interface and source review.

1. Inventory every route to installation

List the fleet client, technician application, local maintenance UI, scheduled jobs and supported recovery service. Identify which routes can reach the same target slots or shared boot metadata. Two processes using different front ends can still modify the same installation resources.

Choose one broker that accepts requests from all ordinary actors. Its record should contain request identity, actor class, approved artifact identity, target scope, admission decision, dispatch state and completion evidence. An actor’s right to request an update is separate from current ownership of the update operation.

This design assumes the product’s existing access policy makes the broker authoritative. A privileged bypass route outside that policy can defeat its serialization. Document exceptional recovery paths and their exclusion requirements; do not claim that adding a lock file constrains every privileged program.

Fleet and local requests enter one broker, which retains ownership across session timeout or lost replies until the installer outcome is reconciled.
Original broker ownership model. It does not add a RAUC cancellation or exactly-once API, and the public Operation property is not used as a lock.

2. Distinguish a request reply from installation completion

The 1.14 D-Bus reference describes InstallBundle as nonblocking. Completion is reported later through Completed, whose argument is a result code. The optional transaction-id identifies an installation transaction; the global Operation property reports an operation state.

Subscribe and establish the broker’s operation record before dispatch. A successful method reply means the request progressed through admission, not that the firmware is installed or healthy. A transport failure while waiting for the reply may leave the result unknown. Do not automatically issue the same request again from a second client.

The completion signal does not carry the caller’s request identity in that documented interface. The broker therefore needs a reliable association between its sole in-flight operation and the observed signal, including daemon-instance continuity. A transaction UUID is useful correlation data, but it is not a documented exactly-once deduplication service.

3. Do not use an idle-property read as a lock

Reading an idle state and then submitting a request leaves a race with another actor. The tagged service implementation checks an internal busy state when handling installation. Importantly, its rejected-request error path sets the public Operation property to idle, including after the busy check fails. Thus, in this version, a competing request can create a misleading public idle observation.

The tagged installer code sets internal busy before starting the installation thread and clears it after completion cleanup. The public property and internal admission guard are different state. This source observation is not a runtime reproduction or a claim about later releases.

Keep the broker’s accepted operation owned despite an isolated idle property update. Reconcile the result using the supported completion path and qualified restart recovery. Include this exact competing-request case in integration testing, rather than assuming a dashboard property is authoritative proof that no write is active.

4. Define ownership transitions explicitly

Event Ownership action Result shown to requester
New eligible request while free Reserve one operation record before dispatch Admitted, installation outcome pending
Another actor requests while owned Reject or queue under a bounded policy Busy with a non-secret operation reference
Identical requester retry Return the existing broker record Current known state, no automatic redispatch
Method response is lost Retain unresolved ownership Acceptance uncertain; reconciliation required
Owner’s UI session or lease expires Remove interactive control if required, retain operation ownership Operation continues or outcome remains unknown
Qualified completion or restart reconciliation Finalize the record and evaluate release conditions Actual result, with later boot state separate

Queueing requires fresh eligibility checks when the request reaches the front. A technician’s old request should not silently run hours later after a newer release, maintenance window or authorization decision has changed. A reject-with-status policy is often simpler than an invisible installation queue.

5. Persist the ambiguity across broker restarts

Before sending a request, persist enough approved, non-secret intent to recognize an interrupted dispatch. There is no atomic transaction spanning ordinary broker storage and a remote D-Bus method call. A crash between those operations must therefore recover as possibly dispatched until evidence resolves it.

After restart, compare the saved intent with daemon continuity, supported status records, target state and available transaction evidence. If the evidence cannot distinguish “never started” from “started and response lost,” hold admission and surface that uncertainty. Resetting the broker to FREE because its old process disappeared is unsafe.

Likewise, a device reboot is not a universal ownership-release event. The installation may have been interrupted, completed before reboot, or advanced to a trial boot. Reconciliation must establish the product’s actual recovery state before another writer is admitted.

6. Qualify races with two controlled clients

  1. Submit simultaneous requests for different approved development bundles.
  2. Lose one method reply after dispatch and retry through the broker.
  3. Expire the requesting actor’s session while installation continues.
  4. Restart the broker with a persisted possibly-dispatched record.
  5. Reject a competing RAUC request and observe both public Operation and the original operation’s completion.
  6. Deliver a delayed completion indication after a daemon or device restart.

Use recoverable test devices, isolated outputs and preserved data. Require at most one admitted writer, correct result attribution and a bounded unresolved-state policy. These are proposed tests, not claimed results. Do not use process termination during flash writes as a shortcut for producing every fault.

Hypothetical technician collision

A fleet installation is active when a technician selects another bundle. The broker returns busy and the current operation reference. If the technician closes the application, the fleet installation remains owned; no timeout hands its slots to another requester.

After the actual installation result is reconciled, the technician can make a fresh request under the current approval and scheduling policy. The acceptance criterion is clear ownership through uncertain communication, not merely a mutex around the first method call.

Similar Posts