Task · OPN-0062

Stop NetFlow intake before the correlator final flush

Description

The log shutdown path flushes and stops the flow correlator while the NetFlow socket and workers are still active. A datagram accepted in that interval is counted into metrics and inserted into an already-stopped correlator; held repair records are also flushed into it later. No second correlator flush or dropped-record accounting occurs, so per-flow logs can disappear during ordinary graceful shutdown.

Acceptance Criteria

Definition of Done

Implementation Plan

Add a lifecycle regression around the shutdown seam, watch it fail for the post-flush intake window, then reorder shutdown ownership so the listener and processor quiesce before the final correlator flush and before the log pipeline drain.

Wave 6 correction: add an end-to-end shutdown regression using the real flowlog Bridge and pipeline; keep the bridge callback live through AfterSourcesStopped and clear it only after the correlator final flush has enqueued; verify the sink receives the pending flow and the dropped counter does not move.

Implementation Notes

Wave 6 audit disproved AC2 in the real bridge lifecycle: pipeline cancellation makes Bridge.Run clear its emit callback before AfterSourcesStopped invokes corr.Flush, so pending flow logs increment the bridge dropped count instead of entering the still-open queue. The prior shutdown regression used a direct sink and could not observe this seam.

Wave 6 final integration: the real flowlog bridge stays bound through the correlator flush and is explicitly unbound afterward. Regression and full repository gate passed at 2389ac3b.

Final Summary

Fixed by 8962f470. Shutdown now waits for log push sources, NetFlow listener/workers and the release ticker, then performs one processor flush and one correlator flush before the log queue closes. The pre-fix regression failed with a stranded held record; targeted checks passed: just test TestShutdownFlowQuiescesBeforeFinalFlush and just test TestPushSourceDoesNotBlockStop. Integrated just check passed. CodeRabbit took two completed passes: pass 1 found the valid Zenarmor quiescence gap; pass 2 completed with zero findings.

Wave 6 supersession: fixed at 2389ac3b. NetFlow producers quiesce before one final processor/correlator drain; the real bridge remains bound until that drain enqueues, then unbinds. The pre-fix regression lost the held flow and moved the dropped counter; the fixed regression and final just check passed.

View the source file on GitHub