Cluster Topology — Deprecation Decision
Status: Decided 2026-05-30. Supersedes the observability cluster log-aggregation topology effort (PR #159 and the three-PR plan it opened).
Decision
We will not build the observability cluster topology — multi-destination log forwarding, mesh / multi-hop, receiver-side dedup, and path[] loop-prevention — nor a dedicated forwarding driver. PR #159 is closed and its branch discarded; none of that code reaches main.
Node→hub reporting is already covered by existing, merged capability, and that is what we rely on:
push_to_hub(apps/alerts/management/commands/push_to_hub.py) — a node runs its own checkers on a cron and POSTs the results to a hub’sPOST /alerts/webhook/cluster/, signed with HMAC-SHA256 (X-Cluster-Signature, secretWEBHOOK_SECRET_CLUSTER). Single hop, and faithful: it carries status, severity, timestamps, labels, metrics, andinstance_id.- Inbound
ClusterDriver(apps/alerts/drivers/cluster.py) — ingests those payloads into the hub’s incident list, so one host becomes the single pane of glass. - The pipeline +
notifystage — the polymorphic, per-node “IFTTT” reporting surface. Each node configures its ownNotificationChannelrows and pipeline definitions: if this alert fires, then run this pipeline, whose notify stage fans out to Slack, PagerDuty, email, or a Generic webhook (including another instance). The operator wires whatever shape they want from existing primitives.
Context
A prior effort (docs/plans/2026-05-25-observability-cluster-topology-design.md and -impl.md, both preserved in closed PR #159) proposed a new cluster log-aggregation layer in apps/observability: a ClusterDestination model, a cluster_dest_* CLI family, record_id / path[] fields on every log record, APIKey.owner_instance_id, a new POST /cluster/logs/<stream>/ receive endpoint with per-host API-key auth, an LRU dedup cache, and a four-scenario loop-prevention scheme for arbitrary mesh topologies.
On review this was judged to be solving problems we do not have. The intended use case is modest: each node monitors itself (via cron) and reports to one central hub so everything is watchable in one place. That is single-hop fan-in, which the existing channel already does.
Rationale
- Duplicated transport. The proposal reinvented a node→hub channel (push, receive, auth, a destination registry) when
push_to_hub+ the inboundClusterDriver+ the HMAC webhook already provide exactly that. - YAGNI. Mesh, multi-hop forwarding, dedup, and loop-prevention only earn their cost in arbitrary topologies. Single-hop fan-in has no cycles to break and no duplicates to suppress.
- Smaller security surface. A parallel
/cluster/logs/endpoint, per-host API keys, and a DB-stored destination registry add attack surface and secret-handling for no current benefit. Keeping one signed channel is easier to reason about. - The pipeline is already the IFTTT engine. Reporting belongs in the
notifystage, where it is per-node configurable and composes with the other notification drivers — not in a bespoke side-channel.
Scope — what is deprecated
All of the following lived only on the feat/observability-cluster-topology branch and never reached main; they are abandoned with the closed PR #159:
- The
ClusterDestinationmodel, its migration, and admin registration. - The
cluster_dest_*management commands (add,list,show,remove,toggle,forward,doctor) and thebin/cli/cluster.shdestination menu. - The
record_idandpath[]fields stamped byJsonLineFormatter. APIKey.owner_instance_id.- The three-PR plan (
2026-05-25-observability-cluster-topology-*). - The proposed
clusternotify driver (considered as an alternative; never built).
What we keep
push_to_hub(cron-driven, faithful, HMAC-signed, single hop) — unchanged.- The inbound
ClusterDriverandPOST /alerts/webhook/cluster/ingestion path. - The
notifystage and its existing drivers (Email, Slack, PagerDuty, Generic) for ad-hoc, per-node reporting — including pointing a Generic channel at another instance’s/alerts/webhook/.
If real log aggregation or mesh is ever needed
Adopt an existing, battle-tested tool rather than building one in-house. Options: Fluent Bit, Vector, Grafana Loki + Promtail, rsyslog, or the OpenTelemetry Collector. These already solve batching, backpressure, dedup, multi-hop fan-in, TLS/auth, and loop avoidance — the exact problems the in-house topology tried to reinvent. Building that layer in Django would be a maintenance liability with no differentiation.
Deferred decision
When such a tool is actually adopted, revisit (and only then):
- Whether
push_to_hubis retained, replaced, or made pipeline-native (run inside a scheduled pipeline’s notify stage rather than as a standalone cron command). - Whether the inbound
ClusterDriverremains the hub’s ingestion path or is superseded by the adopted tool’s own ingestion.
These are intentionally left open. Settling them before there is a concrete aggregation requirement would be premature.
Consequences
- The
cluster_dest_doctorreview fixes and the rest of the PR-1 code are abandoned with the branch (preserved for the record in closed PR #159). apps/observabilitygains no cluster-forwarding surface; its role stays “structured logging, heartbeats, log reader.”- Operators wanting central monitoring use the existing
push_to_hub+ cluster webhook path; per-node ad-hoc reporting uses thenotifystage.