The stats model assumes one QUIC backend (pico or mvfst) at a time. When both
listeners run simultaneously, their collectors both register with StatsRegistry
and aggregateAsync() sums their snapshots field-wise into the same StatsSnapshot
slots. There's no way to distinguish pico vs mvfst contributions in the output.
Affects all shared QUIC counter/histogram fields (quicPacketsSent, RTT
histograms, etc.).
Fix properly before adding per-backend fields — options:
- Split snapshot slots by backend (STATS_PICO_* vs STATS_MVFST_*)
- Add a backend= label at Prometheus export time (requires per-collector metadata)
There's a third stack now: ProxygenQmux. It deliberately registers no
QuicStatsCollector (qmux runs over TCP, not mvfst), so it doesn't pollute the
quic* counters. It does register EventBase collectors, which exposes a related
bug below.
Adjacent bug: EVB collector double-registration
Same root cause — one shared registry and one shared ioExecutor across all
listeners. MoqxRelayServer and MoqxQmuxRelayServer each loop over every EVB in
the shared ioExecutor and create an EventBaseStatsCollector for it. Configure
two such listeners and each shared EVB ends up with two collectors: both land in
the registry's collector list (which never dedups), but setObserver() and the
EventBaseLocal entry each keep only the last one. The orphaned collector stays
in the aggregation list contributing zeros, and findEvbCollector only ever
resolves to the survivor.
The stats model assumes one QUIC backend (pico or mvfst) at a time. When both
listeners run simultaneously, their collectors both register with StatsRegistry
and aggregateAsync() sums their snapshots field-wise into the same StatsSnapshot
slots. There's no way to distinguish pico vs mvfst contributions in the output.
Affects all shared QUIC counter/histogram fields (quicPacketsSent, RTT
histograms, etc.).
Fix properly before adding per-backend fields — options:
There's a third stack now: ProxygenQmux. It deliberately registers no
QuicStatsCollector (qmux runs over TCP, not mvfst), so it doesn't pollute the
quic* counters. It does register EventBase collectors, which exposes a related
bug below.
Adjacent bug: EVB collector double-registration
Same root cause — one shared registry and one shared ioExecutor across all
listeners. MoqxRelayServer and MoqxQmuxRelayServer each loop over every EVB in
the shared ioExecutor and create an EventBaseStatsCollector for it. Configure
two such listeners and each shared EVB ends up with two collectors: both land in
the registry's collector list (which never dedups), but setObserver() and the
EventBaseLocal entry each keep only the last one. The orphaned collector stays
in the aggregation list contributing zeros, and findEvbCollector only ever
resolves to the survivor.