a5256e9b12
'Pattern 4: Integration Routing' — RouteIntegrationCallAsync → SiteEnvelope(IntegrationCallRequest) → SiteCommunicationActor integration handler — was plumbed end to end but connected at neither end: no producer (zero callers) and no handler (AkkaHostedService never registered LocalHandlerType.Integration). It was an early scaffold the architecture routed around — the brokered External→Central→Site→Central round-trip is served by the Inbound API's routed-site-script path (the RouteTo* verbs, driven from CommunicationServiceInstanceRouter), which is live, tested, and shares IntegrationTimeout. Decision (#32): delete. Removed the IntegrationCall{Request,Response} messages, RouteIntegrationCallAsync, the SiteCommunicationActor receive block + _integrationHandler field + LocalHandlerType.Integration, and the four tests that covered them (2 actor, 2 message-contract, 1 dispatcher- reject, 1 mapper-reject). KEPT IntegrationTimeout — it is the live timeout for the RouteTo* verbs. Updated the exclusion-narrative comments (proto/mapper/dispatcher), design §4, the components doc timeout table, and marked the known-issue RESOLVED. Full solution build clean (0/0); Communication 634 + Host 421 green. Net -172/+20 across 14 files. Not in the gRPC proto (was deliberately excluded there), so no wire-format change.
69 lines
4.1 KiB
Markdown
69 lines
4.1 KiB
Markdown
# Integration call routing (`IntegrationCallRequest`) is dead on both ends
|
||
|
||
**Date:** 2026-07-22 · **Status:** RESOLVED (DELETED 2026-07-23) · **Tracked:** Gitea
|
||
[#32](https://gitea.dohertylan.com/dohertj2/ScadaBridge/issues/32) (filed 2026-07-23) · **Severity:**
|
||
Low (no runtime impact — the path cannot be reached) · **Area:** Central–Site Communication
|
||
|
||
> **Resolution (2026-07-23):** Decision = **delete** (option 1 below). Removed the
|
||
> `IntegrationCallRequest`/`IntegrationCallResponse` messages, `CommunicationService.RouteIntegrationCallAsync`,
|
||
> the `SiteCommunicationActor` receive block + `_integrationHandler` field + `LocalHandlerType.Integration`,
|
||
> and the four tests that covered them. `IntegrationTimeout` was **kept** — it is the live timeout for the
|
||
> Inbound API's `RouteTo*` verbs, which are the actual implementation of this "External → Central → Site →
|
||
> Central" pattern (design §4). The narrative comments that documented the exclusion (proto/mapper/dispatcher)
|
||
> were updated. Full solution build clean; Communication suite 634 green. This note is retained as the record.
|
||
|
||
## What
|
||
|
||
"Pattern 4: Integration Routing" — `CommunicationService.RouteIntegrationCallAsync` →
|
||
`SiteEnvelope(IntegrationCallRequest)` → `SiteCommunicationActor` → an integration handler — is
|
||
plumbed end to end but connected at neither end.
|
||
|
||
- **No producer.** `RouteIntegrationCallAsync` (`CommunicationService.cs`, "Pattern 4") has **zero
|
||
callers** in `src/` or `tests/`. It is the only one of `CommunicationService`'s command methods
|
||
with none.
|
||
- **No handler.** `SiteCommunicationActor` forwards to `_integrationHandler` when one is
|
||
registered, but `RegisterLocalHandler(LocalHandlerType.Integration, …)` appears **only** in
|
||
`SiteCommunicationActorTests.cs`. `AkkaHostedService` registers the other three handler types
|
||
(`Artifacts`, `EventLog`, `ParkedMessages`) and never this one.
|
||
|
||
So if anything ever did call it, the site would answer
|
||
`IntegrationCallResponse(Success: false, Error: "Integration handler not available")`
|
||
(`SiteCommunicationActor.cs`, Pattern 4) — and the two tests that exercise the path both register
|
||
the handler themselves first, which is why the suite has never noticed.
|
||
|
||
Do not confuse this with the **Inbound API**'s routed-site-script path, which is live, tested, and
|
||
uses different messages entirely. This is a separate, unused routing pattern that predates it.
|
||
|
||
## Why it is recorded rather than fixed
|
||
|
||
Found during the recon for the ClusterClient→gRPC transport migration
|
||
([`docs/plans/2026-07-22-clusterclient-to-grpc-plan.md`](../plans/2026-07-22-clusterclient-to-grpc-plan.md),
|
||
T0.2), which had to enumerate every command crossing the site↔central boundary. Of the **29**
|
||
command types, this is the one that is excluded: **28 migrate to the gRPC contract.**
|
||
|
||
Porting it would mean designing a proto contract, a `oneof` slot and round-trip mapper tests for a
|
||
verb no caller can invoke and no site can service — and enshrining it on a wire format whose
|
||
evolution rules are additive-only, so an unused RPC slot is permanent. Deleting it during a
|
||
transport migration would mix an unrelated behavioural change into a change whose whole value is
|
||
that behaviour is identical. Hence: excluded from the contract, behaviour untouched, decision
|
||
deferred to its own change.
|
||
|
||
## Decision needed
|
||
|
||
Either:
|
||
|
||
1. **Delete** — remove `RouteIntegrationCallAsync`, the `IntegrationCallRequest`/`Response`
|
||
messages, the `SiteCommunicationActor` receive block, `LocalHandlerType.Integration`, and the
|
||
three tests that cover them. This is the default if no consumer is planned.
|
||
2. **Wire** — register a real integration handler on site nodes and give the method a caller. This
|
||
only makes sense if there is a requirement it serves; none is recorded in
|
||
`docs/requirements/`.
|
||
|
||
Whichever is chosen, do it **before Phase 4** of the migration, since Phase 4 deletes the Akka
|
||
transport underneath this path. If it is still dead at that point, option 1 is forced.
|
||
|
||
## Filing
|
||
|
||
To be filed as a Gitea issue on `dohertj2/scadabridge` by the repo owner — this note is the
|
||
in-repo record of the finding and of the migration exclusion it justifies.
|