You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
FreeDMR/docs/freedmr-2/adr/0013-worker-process-capacit...

3.7 KiB

ADR 0013: Worker Process Capacity Scaling

Status

Proposed

Context

FreeDMR currently relies heavily on a single Python process, Twisted reactor callbacks, and in-memory mutable state inherited from the HBLink-era architecture.

This is useful as an initial safety boundary because it avoids many shared-memory races, but it also creates practical capacity limits and makes some kinds of expensive work unsafe in the packet path.

CPython's GIL and single-reactor execution mean that CPU-bound work, reporting fanout, SQL/global export, analytics, and future codec/transcoding work should not be assumed to scale inside one process.

At the same time, FreeDMR's packet/routing state is subtle and protocol-sensitive. Moving it prematurely across process boundaries could introduce latency, ordering bugs, stale packet replay, duplicate packets, routing loops, broken source quench, or incorrect packet mutation.

Decision

FreeDMR 2 will be designed for eventual worker-process scaling, but the first migration stage will keep Twisted as the transport shell and extract/test the routing/subscription core in-process.

The first worker-process targets are non-packet-path or low-risk side effects:

  • Reporting/MQTT publisher.
  • Global lastheard exporter.
  • SQL/database writes.
  • Dashboard aggregation.
  • Alias refresh.
  • Analytics.
  • Packet replay/diagnostics.
  • Future codec/transcoding adjuncts.

Packet-plane routing may move behind a process/message boundary later, but only after state ownership, subscription lookup, stream lifecycle, loop control, source quench, and packet mutation semantics are covered by deterministic, UDP, and live RF tests.

FreeDMR 2 prefers explicit process/actor ownership boundaries over shared-memory threading or no-GIL Python for authoritative routing state.

Rationale

  • Worker processes provide clearer ownership and failure boundaries.
  • Explicit messages are easier to test than shared mutable dictionaries.
  • Reporting/export failures must not affect packet routing.
  • FreeDMR should be able to scale beyond one reactor process without making ordinary small deployments complex.
  • No-GIL Python does not remove the need for state ownership discipline.
  • A process model better matches FreeDMR's distributed-system nature: packet events, routing decisions, control messages, and reporting events are already conceptually separate.

Consequences

Positive:

  • Clearer state ownership.
  • Improved future capacity.
  • Safer isolation of reporting/export/database work.
  • Better failure containment.
  • Better testability of message boundaries.
  • Easier future sharding by client, TG, stream, listener, or mesh peer.

Negative:

  • More implementation complexity.
  • Message schemas must be designed and versioned.
  • IPC adds latency and failure modes.
  • Routing-worker split requires strong tests.
  • Worker supervision and restart policy become part of the system design.

Compatibility

FreeDMR 1.x/current code remains live until FreeDMR 2 is ready.

Initial FreeDMR 2 worker work should not change packet semantics.

Legacy dashboard/reporting compatibility, if required, belongs in reporting/export adapters, not in the packet core.

A single-process deployment must remain supported for small servers.

Testing Requirements

Before any packet-plane worker split:

  • Deterministic harness coverage of the state machine.
  • Message-boundary equivalence tests.
  • UDP black-box equivalence tests.
  • Packet byte preservation tests.
  • Allowed rewrite-region tests.
  • Source quench/STUN/loop-control tests.
  • Duplicate/out-of-order tests.
  • Worker crash/restart tests.
  • Stale packet replay prevention tests.
  • Queue backpressure tests.
  • Live RF validation for protocol-visible behaviour.

Powered by TurnKey Linux.