Files
pnoker 21e0bae93c refactor(driver): collapse duplicated hex and checksum helpers into codecutil
five drivers carried private bytesToHex copies and three carried
hexToBytes variants, while mbus/dlt645 frames each implemented the same
sum checksum:

- codecutil.bytesToHex now uses hexformat uppercase, matching what all
  five private copies already emitted (zero display change)
- codecutil.hexToBytes added: whitespace-tolerant, blank-to-empty,
  mixed-case input
- codecutil.sumChecksum added as the shared mbus/dlt645 frame checksum
  and both frame classes delegate to it
- dlt645's inline hex loop replaced by codecutil.hexTobytes
- fins' private bcd copy kept deliberately: codecutil's bcd variant
  strips leading zeros, a different protocol semantic
2026-09-18 19:45:24 +08:00
..

DC3 Common Driver

Overview

dc3-common-driver is the shared driver dependency module of the IoT DC3 platform. It provides the driver SDK shared by all protocol drivers, including auto-registration with Manager Center, manager-backed runtime ownership (membership, assignments, and fencing tokens are persisted in PostgreSQL by the Manager Center), metadata sync, RabbitMQ command handling, durable telemetry publication, and scheduled data collection. Redis is not part of the driver coordination path.

Module Information

  • Group ID: io.github.pnoker
  • Artifact ID: dc3-common-driver

Key Components

Component Purpose
DriverInitRunner Registers logical metadata and starts the runtime lease
DriverLeaseRenewScheduleJob Renews membership and installs streamed ownership snapshots
DriverEnvironmentConfig Derives immutable node, service, host, and client identities
BufferServiceImpl SQLite outbox deleted only after broker ACK and routability
RabbitMQ Consumers Validates node/fencing before executing directed commands
Scheduled Jobs Reads only devices currently owned by the runtime node
DriverTopicConfig Creates expiring per-node command queues and bindings

Driver Registration Flow

Driver startup
  → DriverInitRunner
    → gRPC: dc3-center-manager / DriverApi.DriverRegister
      ← Returns: logical driver and protocol metadata
    → gRPC stream: DriverApi.RenewLease
      ← Returns: bounded device-lease pages, assignment version, fencing tokens
    → Atomically install the ownership snapshot after stream completion
    → Subscribe to metadata queue: dc3.q.metadata.driver.{serviceName}
    → Subscribe to point-command queue: dc3.q.point_command.{serviceName}.{node}
    → Subscribe to custom-command queue: dc3.q.command.{serviceName}.{node}

Manager Center stores runtime membership, device assignments, assignment revisions, and fencing tokens in PostgreSQL. Rendezvous hashing assigns each active device to exactly one live node. Stable heartbeats read only membership and one device-revision row; full device scans happen only after membership or device-set changes. Both reconciliation and gRPC delivery use keyset pages, so no manager request materializes every device in memory.

RabbitMQ Integration

Exchange Queue Purpose
dc3.e.metadata dc3.q.metadata.driver.{service} Receive configuration changes
dc3.e.point_command dc3.q.point_command.{service}.{node} Receive owner-directed point commands
dc3.e.command dc3.q.command.{service}.{node} Receive owner-directed custom commands
dc3.e.value — Publish point values to Data Center

The optional dc3.rabbit.tag system property prefixes runtime names; use RabbitConstant and DriverTopicConfig as the authoritative definitions.

Delivery and Failure Semantics

  • A point value receives an immutable message ID, schema version, node sequence, owner node, and fencing token.
  • Every point value is written to the mandatory SQLite outbox using WAL with full synchronous durability before publish. A row is removed only after RabbitMQ publisher confirm ACK and no mandatory-return signal. NACK, unroutable, timeout, and synchronous failures remain durable and use capped exponential backoff; there is no retry-count or size-based data eviction.
  • List-based reports are inserted in one SQLite transaction before the first RabbitMQ publish, preserving durability while amortizing FULL-synchronous fsync cost for high-volume protocol frames.
  • Every driver runtime must own an exclusive outbox directory on persistent storage. Do not mount the same SQLite file into multiple driver processes or replicas. The supplied Compose stacks mount one shared driver_data volume and isolate drivers by mount path (/dc3-driver/dc3-driver-<name>/dc3/data), so each driver's outbox lives in its own service-name-scoped subdirectory; an orchestrator must provide equivalent per-pod persistent storage. This means the compose scale/swarm stacks keep drivers at one replica each (two replicas of one driver would open the same outbox file); Kubernetes/Helm pods each get their own emptyDir, so drivers may scale there.
  • A driver stops reads, writes, and telemetry immediately when its local lease expires. Manager and Data Center also reject stale owners by node and fencing token, so a paused or partitioned process cannot resume as an owner.
  • Command execution is at-least-once across process crashes. Protocol implementations should use the command ID when the physical device supports idempotency; no platform can guarantee exactly-once physical I/O after a crash without device-side idempotency.

Runtime Settings

Property Default Meaning
dc3.driver.lease.seconds 30 Manager-issued runtime lease; valid range is 10–120 seconds
dc3.driver.lease.renew-cron 0/10 * * * * ? Lease renewal schedule; keep comfortably below the lease
dc3.driver.lease.queue-expires-millis 300000 Removes unused per-node command queues after pod churn
dc3.driver.buffer.db-path dc3/data/driver/buffer.db Mandatory SQLite outbox path on runtime-exclusive persistent storage
dc3.driver.buffer.batch-size 200 Maximum outbox rows attempted per republish tick
dc3.driver.buffer.max-backoff-seconds 600 Maximum per-message republish backoff

Build Instructions

mvn -s .mvn/settings.xml -pl dc3-common/dc3-common-driver -am package

Testing

Run the module tests from the repository root:

mvn -s .mvn/settings.xml -pl dc3-common/dc3-common-driver -am test
  • All dc3-driver-* modules — Consume this SDK
  • dc3-api-driver — gRPC contracts consumed by this SDK
  • dc3-mq-core / dc3-mq-rabbitmq — broker-neutral messaging port and RabbitMQ adapter
  • dc3-common-constant — RabbitConstant routing key prefixes