fix(store-and-forward): resolve S&F delivery + replication wiring (3 Critical findings)
Resolves StoreAndForward-001, ExternalSystemGateway-001, NotificationService-001 — one systemic gap where buffered messages were persisted but never delivered, and the active node never replicated its buffer to the standby. Delivery handlers (ExternalSystemGateway-001 / NotificationService-001): - AkkaHostedService registers delivery handlers for the ExternalSystem, CachedDbWrite and Notification categories after StoreAndForwardService starts; each resolves its scoped consumer in a fresh DI scope. - ExternalSystemClient, DatabaseGateway and NotificationDeliveryService each gain a DeliverBufferedAsync method: re-resolve the target and re-attempt delivery, returning true/false/throwing per the transient-vs-permanent contract. - EnqueueAsync gains an attemptImmediateDelivery flag; CachedCallAsync and NotificationDeliveryService.SendAsync pass false (they already attempted delivery themselves) so registering a handler does not dispatch twice. Replication (StoreAndForward-001): - ReplicationService is injected into StoreAndForwardService; a new BufferAsync helper replicates every enqueue, and successful-retry removes and parks are replicated too. Fire-and-forget, no-op when replication is disabled. Tests: StoreAndForwardReplicationTests (Add/Remove/Park observed), attemptImmediateDelivery behaviour, and DeliverBufferedAsync paths for each consumer. Full solution builds; StoreAndForward/ExternalSystemGateway/ NotificationService suites green.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
| Last reviewed | 2026-05-16 |
|
||||
| Reviewer | claude-agent |
|
||||
| Commit reviewed | `9c60592` |
|
||||
| Open findings | 14 |
|
||||
| Open findings | 13 |
|
||||
|
||||
## Summary
|
||||
|
||||
@@ -53,7 +53,7 @@ requirements (timeout, retry settings) that are declared but not implemented.
|
||||
|--|--|
|
||||
| Severity | Critical |
|
||||
| Category | Error handling & resilience |
|
||||
| Status | Open |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.ExternalSystemGateway/ExternalSystemClient.cs:109`, `src/ScadaLink.ExternalSystemGateway/DatabaseGateway.cs:81` |
|
||||
|
||||
**Description**
|
||||
@@ -89,7 +89,19 @@ verifies it is delivered by a retry sweep.
|
||||
|
||||
**Resolution**
|
||||
|
||||
_Unresolved._
|
||||
Resolved 2026-05-16. Delivery handlers for `StoreAndForwardCategory.ExternalSystem` and
|
||||
`CachedDbWrite` are now registered at site startup in `AkkaHostedService`, after
|
||||
`StoreAndForwardService.StartAsync()`. Each handler resolves its consumer in a fresh DI
|
||||
scope and calls a new `DeliverBufferedAsync`: `ExternalSystemClient.DeliverBufferedAsync`
|
||||
re-resolves the system/method and re-invokes `InvokeHttpAsync`, and
|
||||
`DatabaseGateway.DeliverBufferedAsync` executes the buffered SQL — each returning `true`
|
||||
on success, `false` (park) when the target no longer exists or fails permanently, and
|
||||
throwing on transient failure so the engine retries. `EnqueueAsync` gained an
|
||||
`attemptImmediateDelivery` parameter; `CachedCallAsync` passes `false` so registering the
|
||||
handler does not dispatch the request twice (the double-dispatch noted in
|
||||
`ExternalSystemGateway-003`). Regression tests cover the success, target-removed and
|
||||
transient-retry paths. Fixed by the commit whose message references
|
||||
`ExternalSystemGateway-001`.
|
||||
|
||||
### ExternalSystemGateway-002 — Per-system call timeout is never applied to HTTP requests
|
||||
|
||||
|
||||
Reference in New Issue
Block a user