From 7676ab93c444626dbf5fc927cecf6576408a56bb Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Mon, 20 Jul 2026 22:04:28 -0400 Subject: [PATCH] =?UTF-8?q?chore(localdb):=20rig=20config=20=E2=80=94=20co?= =?UTF-8?q?nsolidated=20path=20everywhere,=20replication=20on=20the=20site?= =?UTF-8?q?-a=20pair?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every driver-role node gets a per-node named volume at /app/data and LocalDb__Path=/app/data/otopcua-localdb.db so the pair-local config cache survives container recreates. The site-a pair enables replication (SyncListenPort 9001, a-1 dials a-2, shared dev-only ApiKey, MaxBatchSize 16); the central and site-b pairs stay default-OFF — site-b is the pin the live gate's check 8 verifies. docker compose config validates; rig not brought up (live gate owns runs). --- docker-dev/docker-compose.yml | 57 +++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/docker-dev/docker-compose.yml b/docker-dev/docker-compose.yml index af4cd50e..2d2d712d 100644 --- a/docker-dev/docker-compose.yml +++ b/docker-dev/docker-compose.yml @@ -224,8 +224,15 @@ services: Serilog__MinimumLevel__Override__Microsoft.EntityFrameworkCore: "Warning" Serilog__MinimumLevel__Override__Microsoft.AspNetCore: "Warning" GALAXY_MXGW_API_KEY: "${GALAXY_MXGW_API_KEY:-mxgw_otopcua2_GI7-tNozYE6cXGUSgEzL3AHDV7bYcYIHdMwKYgyHdX4}" + # Consolidated pair-local config cache (ZB.MOM.WW.LocalDb). Every driver-role node + # (central is admin,driver) gets one, on a per-node named volume so the cache survives + # container recreates. The central pair leaves replication OFF (default) — only the + # site-a pair replicates, as the enablement demo; site-b is the default-OFF pin. + LocalDb__Path: "/app/data/otopcua-localdb.db" ports: - "4840:4840" + volumes: + - otopcua-localdb-central-1:/app/data central-2: <<: *otopcua-host @@ -283,8 +290,12 @@ services: Serilog__MinimumLevel__Override__Microsoft.EntityFrameworkCore: "Warning" Serilog__MinimumLevel__Override__Microsoft.AspNetCore: "Warning" GALAXY_MXGW_API_KEY: "${GALAXY_MXGW_API_KEY:-mxgw_otopcua2_GI7-tNozYE6cXGUSgEzL3AHDV7bYcYIHdMwKYgyHdX4}" + # Pair-local config cache; central pair leaves replication OFF (see central-1). + LocalDb__Path: "/app/data/otopcua-localdb.db" ports: - "4841:4840" + volumes: + - otopcua-localdb-central-2:/app/data # ── Site A cluster (2-node driver-only) ───────────────────────────────────── # Driver-only members of the single mesh, scoped to SITE-A by ClusterId. No UI, @@ -313,8 +324,24 @@ services: # Resolved at runtime by GalaxyDriver.ResolveApiKey when a DriverInstance's # Gateway.ApiKeySecretRef = "env:GALAXY_MXGW_API_KEY". GALAXY_MXGW_API_KEY: "${GALAXY_MXGW_API_KEY:-mxgw_otopcua2_GI7-tNozYE6cXGUSgEzL3AHDV7bYcYIHdMwKYgyHdX4}" + # Pair-local config cache + REPLICATION ON — the site-a pair is the enablement demo. + # site-a-1 is the initiator: it binds the h2c sync listener on 9001 AND dials the peer. + # Setting SyncListenPort makes Program.cs add a dedicated Http2-only Kestrel listener and + # re-bind the primary HTTP port (an explicit Listen* otherwise discards ASPNETCORE_URLS). + LocalDb__Path: "/app/data/otopcua-localdb.db" + LocalDb__SyncListenPort: "9001" + LocalDb__Replication__PeerAddress: "http://site-a-2:9001" + # DEV-ONLY committed key (rig philosophy — like the SQL password + secrets KEK above). It + # MUST be byte-identical on both nodes: the interceptor is fail-closed, so any mismatch + # silently stops the pair converging. NEVER reuse this key outside this local dev rig. + LocalDb__Replication__ApiKey: "dev-site-a-localdb-sync-key" + # Row-count batching against gRPC's 4 MB message cap; artifact chunk rows are ≈171 KB, so + # 16 × 171 KB ≈ 2.7 MB stays under the cap with headroom. + LocalDb__Replication__MaxBatchSize: "16" ports: - "4842:4840" + volumes: + - otopcua-localdb-site-a-1:/app/data site-a-2: <<: *otopcua-host @@ -334,8 +361,18 @@ services: Serilog__MinimumLevel__Override__Microsoft.EntityFrameworkCore: "Warning" Serilog__MinimumLevel__Override__Microsoft.AspNetCore: "Warning" GALAXY_MXGW_API_KEY: "${GALAXY_MXGW_API_KEY:-mxgw_otopcua2_GI7-tNozYE6cXGUSgEzL3AHDV7bYcYIHdMwKYgyHdX4}" + # site-a-2 is the passive half of the replicating pair: it binds the sync listener on 9001 + # but does NOT dial (no PeerAddress). The replication stream is bidirectional, so a-1's + # single dial carries both directions. Same key + MaxBatchSize as a-1 (byte-identical key + # is mandatory — the interceptor fail-closes on a mismatch). + LocalDb__Path: "/app/data/otopcua-localdb.db" + LocalDb__SyncListenPort: "9001" + LocalDb__Replication__ApiKey: "dev-site-a-localdb-sync-key" + LocalDb__Replication__MaxBatchSize: "16" ports: - "4843:4840" + volumes: + - otopcua-localdb-site-a-2:/app/data # ── Site B cluster (2-node driver-only) ───────────────────────────────────── @@ -357,8 +394,14 @@ services: Serilog__MinimumLevel__Override__Microsoft.EntityFrameworkCore: "Warning" Serilog__MinimumLevel__Override__Microsoft.AspNetCore: "Warning" GALAXY_MXGW_API_KEY: "${GALAXY_MXGW_API_KEY:-mxgw_otopcua2_GI7-tNozYE6cXGUSgEzL3AHDV7bYcYIHdMwKYgyHdX4}" + # site-b is the default-OFF pin: it gets the pair-local cache but NO SyncListenPort and NO + # replication config, so no sync listener binds and ISyncStatus stays disconnected/Healthy. + # This is what the live gate's check 8 verifies — the cache works locally with replication off. + LocalDb__Path: "/app/data/otopcua-localdb.db" ports: - "4844:4840" + volumes: + - otopcua-localdb-site-b-1:/app/data site-b-2: <<: *otopcua-host @@ -378,8 +421,12 @@ services: Serilog__MinimumLevel__Override__Microsoft.EntityFrameworkCore: "Warning" Serilog__MinimumLevel__Override__Microsoft.AspNetCore: "Warning" GALAXY_MXGW_API_KEY: "${GALAXY_MXGW_API_KEY:-mxgw_otopcua2_GI7-tNozYE6cXGUSgEzL3AHDV7bYcYIHdMwKYgyHdX4}" + # site-b default-OFF pin (see site-b-1): cache on, replication off. + LocalDb__Path: "/app/data/otopcua-localdb.db" ports: - "4845:4840" + volumes: + - otopcua-localdb-site-b-2:/app/data traefik: image: traefik:v3.1 @@ -400,3 +447,13 @@ services: volumes: # SQL Server data dir — persists the OtOpcUa ConfigDb across container recreates. otopcua-mssql-data: + # Per-node pair-local config-cache (ZB.MOM.WW.LocalDb) files. One volume per node — the + # cache is node-local, not shared; it persists the cached deployment artifact (and, on the + # site-a pair, the replicated oplog state) across container recreates so a node can boot + # from cache after a restart even with central SQL down. + otopcua-localdb-central-1: + otopcua-localdb-central-2: + otopcua-localdb-site-a-1: + otopcua-localdb-site-a-2: + otopcua-localdb-site-b-1: + otopcua-localdb-site-b-2: