Skip to content

v2.0.1

Choose a tag to compare

@emfoursolutions emfoursolutions released this 22 Jul 22:13
· 100 commits to main since this release

Version 2.0.1 - Multi-Server RX Dispatch & Worker Stability

Release Date: July 23, 2026
Focus: Silent data-loss fix for multi-server streams and a long-standing worker-recycling bug that surfaced in 2.0.0

Two hotfixes for issues introduced or first observed in 2.0.0. The RX dispatch bug caused output plugins to silently miss traffic from every TAK server beyond the first when a stream was attached to multiple servers — the postgres archiver made this visible for the first time. The Hypercorn worker was silently recycling every ~1000 requests (roughly every 30 minutes on a healthy deployment), tearing down long-lived stream state and interrupting CoT delivery; this has been present since Hypercorn was introduced but only became observable in 2.0.0 because plugin whitelist gating and buffering output plugins now depend on continuous worker uptime.

No schema changes. No new configuration. Straight upgrade from 2.0.0.


BUG FIXES

RX plugin dispatch now respects the multi-server junction table

Silent data loss for output plugins on multi-server streams — critical

The 2.0.0 many-to-many stream_tak_servers junction table was correctly consulted on the TX side and during worker startup, but the RX-side plugin dispatch query in services/cot_service_integration.py still filtered streams by the legacy single-server tak_server_id column. When a stream was attached to multiple TAK servers, every CoT event received from any server other than the one referenced by the legacy foreign key was silently discarded — the output plugin was never called.

  • Symptom: postgres archiver (or any output plugin) captured traffic from TAK server 1 only; server 2's events were missing entirely with no error log
  • Blast radius: every output plugin — archivers, forwarders, notifiers, external HTTP outputs — attached to any multi-server stream
  • Fix: the RX dispatch query now matches streams via either the legacy foreign key or membership in stream_tak_servers, mirroring the "multi-first, legacy-fallback" pattern already used elsewhere in the codebase. Backward compatible: single-server streams continue to work unchanged. No migration required.

Hypercorn worker no longer recycles every ~1000 requests

Long-lived stream state and buffered plugin data preserved across worker lifetime

The Docker entrypoint launched Hypercorn with --max-requests 1000, a stateless-web-worker recycling pattern that fights TrakBridge's single-long-lived-worker architecture. Every recycle:

  • Tore down every stream worker and TAK server connection
  • Triggered graceful shutdown of the plugin cache (draining buffered state)
  • Interrupted CoT delivery for the ~1–2 second graceful-shutdown window
  • Re-triggered plugin whitelist reload — which in 2.0.0 became a fragile path

The recycling was silent in earlier releases because output plugins had no buffered state and no whitelist gating existed. In 2.0.0 the combination surfaced the bug as observable data loss (buffered rows in the postgres archiver) and unrecoverable startup failures (whitelist reload permission errors on some deployments).

--max-requests has been removed from the Hypercorn command line. The HYPERCORN_MAX_REQUESTS environment variable is no longer honoured; any override in existing compose files is silently ignored. Worker hygiene is now handled by graceful shutdown and container health checks alone.

Full COT service shutdown on process teardown

Output plugin cleanup and pending output stats now flushed on SIGTERM

_cleanup_persistent_cot_service() in services/stream_manager.py only stopped in-flight workers on shutdown; it never awaited QueuedCOTService.shutdown(). That meant:

  • cleanup() hooks on cached output plugins were never called
  • Pending output-stat writes were never flushed to the database
  • Buffering plugins (like the postgres archiver) lost any in-memory queue on SIGTERM

The teardown path now drives the full async shutdown via run_coroutine_threadsafe on the stream manager's event loop, matching the pattern already used for stop_all() and _cleanup_monitoring_services(). A worker-stop fallback remains for the edge case where no event loop is available, with a warning logged to make skipped plugin cleanup visible.


PLUGIN SDK

No SDK version bump. The lifecycle hooks (start(), cleanup()) documented in the 2.0.0 SDK are now correctly driven by core on every configured teardown path: stream reconfig, stream deletion, stream stop/restart, and clean process shutdown.


UPGRADE NOTES

Straight upgrade from 2.0.0. No schema migration, no configuration change required.

Behavioural change: workers now stay up until the container is explicitly restarted. Health-check based hygiene continues as before. If you were relying on periodic worker recycling for any reason (memory cleanup, garbage collection, socket refresh), your Hypercorn worker will now behave like a genuinely long-lived process — plan container restart cadence accordingly.

The HYPERCORN_MAX_REQUESTS environment variable is no longer read. Override entries in existing docker-compose.yml files can be removed at your convenience; leaving them in place is harmless.