historian: QuestDB backend (design + plan) #666

Closed
opened 2026-10-09 15:26:03 -04:00 by dohertj2 · 1 comment
Owner

The pluggable historian work (feat/pluggable-historian, design docs/plans/2026-10-09-pluggable-historian-design.md) added a backend seam, IHistorianBackendProvider, and a SQL Server backend. QuestDB was the third backend in the original request, deferred to a follow-up.

Scope: write a design and plan for a QuestDb provider. It needs all five seams: data source, value writer, alarm writer, provisioning and updater. Points to settle:

  • Typed values and the real status column.
  • Pushing the aggregate set down to QuestDB SAMPLE BY.
  • What HistoryUpdate supports, given QuestDB's limited UPDATE and DELETE.
  • Idempotent outbox redelivery, using a dedup key on (tag, timestamp).
  • Doing this without a new NuGet package, or getting explicit approval for one.

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe

The pluggable historian work (`feat/pluggable-historian`, design `docs/plans/2026-10-09-pluggable-historian-design.md`) added a backend seam, `IHistorianBackendProvider`, and a SQL Server backend. QuestDB was the third backend in the original request, deferred to a follow-up. **Scope:** write a design and plan for a `QuestDb` provider. It needs all five seams: data source, value writer, alarm writer, provisioning and updater. Points to settle: - Typed values and the real status column. - Pushing the aggregate set down to QuestDB `SAMPLE BY`. - What HistoryUpdate supports, given QuestDB's limited UPDATE and DELETE. - Idempotent outbox redelivery, using a dedup key on (tag, timestamp). - Doing this without a new NuGet package, or getting explicit approval for one. Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
Author
Owner

Shipped on master at ee67b637 (merge of feat/questdb-historian).

ServerHistorian:Backend=QuestDb adds a third historian backend at parity with SqlServer:

  • Npgsql/PG wire only, no new packages.
  • Typed values with real status, Processed/AtTime/Events reads, and all five HistoryUpdate operations.
  • Soft delete via a deleted flag plus tombstone rows. QuestDB never receives UPDATE or DELETE; every write is an INSERT under DEDUP UPSERT KEYS(ts, tag).
  • Table TTL retention via ServerHistorian:QuestDb:RetentionDays.

Dialect-free logic moved to Driver.Historian.Sql.Common. One conformance suite runs against both backends: 117 SqlServer and 162 QuestDB integration tests, all green.

The live gate passed all six legs on docker-dev:

  1. Primary-only typed recording.
  2. Raw and UNS HistoryRead matching direct QuestDB queries.
  3. HistoryUpdate codes and denials, including a real outbox-replay redelivery that does not resurrect a deleted row.
  4. 1× recording across failover.
  5. Modbus comms-loss outage marker.
  6. TTL in table metadata.

Evidence: docs/plans/2026-10-10-questdb-historian-live-gate.md. Docs: docs/Historian.md §QuestDB backend and docs/Configuration.md ServerHistorian:QuestDb.

Follow-ups filed from the gate: the crash-failover capture gap (#672) and a FOCAS test flake (#673).

Shipped on `master` at `ee67b637` (merge of `feat/questdb-historian`). `ServerHistorian:Backend=QuestDb` adds a third historian backend at parity with SqlServer: - Npgsql/PG wire only, no new packages. - Typed values with real status, Processed/AtTime/Events reads, and all five HistoryUpdate operations. - Soft delete via a `deleted` flag plus tombstone rows. QuestDB never receives UPDATE or DELETE; every write is an INSERT under `DEDUP UPSERT KEYS(ts, tag)`. - Table TTL retention via `ServerHistorian:QuestDb:RetentionDays`. Dialect-free logic moved to `Driver.Historian.Sql.Common`. One conformance suite runs against both backends: 117 SqlServer and 162 QuestDB integration tests, all green. The live gate passed all six legs on docker-dev: 1. Primary-only typed recording. 2. Raw and UNS HistoryRead matching direct QuestDB queries. 3. HistoryUpdate codes and denials, including a real outbox-replay redelivery that does not resurrect a deleted row. 4. 1× recording across failover. 5. Modbus comms-loss outage marker. 6. TTL in table metadata. Evidence: `docs/plans/2026-10-10-questdb-historian-live-gate.md`. Docs: `docs/Historian.md` §QuestDB backend and `docs/Configuration.md` `ServerHistorian:QuestDb`. Follow-ups filed from the gate: the crash-failover capture gap (#672) and a FOCAS test flake (#673).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#666