refactor(runtime): delete the dead in-place ApplyDelta seam; config change = respawn only (#665)
Since #516 a DriverConfig change is stop + respawn, so DriverSpawnPlan.ToApplyDelta was always empty and the in-place path had no producer. #663 and #664 were both latent bugs in it. This deletes it: - host: ApplyChildDelta, _pendingDelta, HandleApplyResult and HandleDeltaApplied - plan: DriverSpawnPlan.ToApplyDelta - actor: the ApplyDelta, ApplyResult and DeltaApplied messages, the Connected reinit handler and the mid-connect AdoptConfigDuringInit - tests: the actor tests that drove the seam IDriver.ReinitializeAsync and each driver's implementation and unit tests stay. Comments and docs that cited AdoptConfigDuringInit as the reason a driver must release prior state at init now cite the IDriver contract and overlapping retries, which still apply. Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
@@ -95,7 +95,7 @@ public sealed class ModbusDriver
|
||||
/// concurrent operations would dispose each other's freshly-built transport or null
|
||||
/// <c>_transport</c> out from under an in-flight connect. Not hypothetical:
|
||||
/// <c>DriverInstanceActor</c> dispatches initialize on a fire-and-forget <c>Task.Run</c> and
|
||||
/// its <c>AdoptConfigDuringInit</c> can fire twice back to back. Same shape as
|
||||
/// a reconnect retry tick can start a second attempt while the first is still running. Same shape as
|
||||
/// <c>MqttDriver._lifecycleGate</c>.
|
||||
/// </summary>
|
||||
private readonly SemaphoreSlim _lifecycleGate = new(1, 1);
|
||||
@@ -297,9 +297,9 @@ public sealed class ModbusDriver
|
||||
// Release whatever a PREVIOUS initialize published before building the replacements. All
|
||||
// three fields assigned below (_transport, _probeCts, _reprobeCts) were simply overwritten,
|
||||
// so a second initialize on a live driver stranded a connected transport plus two running
|
||||
// background loops that no later dispose could reach. Reachable without any teardown of
|
||||
// ours: DriverInstanceActor re-runs InitializeAsync with no ShutdownAsync when an ApplyDelta
|
||||
// lands while the driver is in Connecting/Reconnecting (AdoptConfigDuringInit).
|
||||
// background loops that no later dispose could reach. The IDriver contract lets a
|
||||
// caller re-initialise a live driver without ShutdownAsync, and DriverInstanceActor's retry tick
|
||||
// can overlap a still-running attempt, so this must not rely on a teardown having happened.
|
||||
// Deliberately NOT the shared TeardownAsync(): that also disposes _poll, which tears down
|
||||
// every ACTIVE SUBSCRIPTION — and nothing re-subscribes them afterwards, because a
|
||||
// mid-life re-initialize is not a shutdown the OPC UA layer knows to re-drive. A caller
|
||||
|
||||
Reference in New Issue
Block a user