ws_service_stats.rs has two suppressions: run_service_collector (line 254) and handle_stats_socket (line 436), both #[allow(clippy::cognitive_complexity)].
What they do
run_service_collector (~90 lines) — resolves the inner container for a service, then polls docker stats --no-stream every 2 seconds in a loop, parses JSON, pushes to history ring, broadcasts to subscribers
handle_stats_socket (~55 lines) — replays history buffer to a newly connected WebSocket client, then runs a tokio::select! loop relaying broadcast receiver output to the socket (same pattern as ws_stats.rs and ws_host_service_stats.rs)
What to do
1. Extract single-poll execution in run_service_collector
Lines 290–323 build exec options, run create_exec + start_exec, accumulate stdout, and parse JSON. Extract:
async fn poll_service_stats(
docker: &bollard::Docker,
coast_container_id: &str,
stats_cmd: &str,
) -> Option<serde_json::Value>
2. Extract history push + broadcast
Lines 325–335 push the new value into the history ring and send to the broadcast channel. Extract (could be shared with ws_host_service_stats.rs and ws_stats.rs):
async fn push_stats_to_history_and_broadcast(
history: &Mutex<HashMap<String, VecDeque<serde_json::Value>>>,
key: &str,
val: serde_json::Value,
tx: &broadcast::Sender<serde_json::Value>,
)
3. Extract history replay for handle_stats_socket
Lines 440+ replay the history ring to the socket. Extract (shared with ws_stats.rs and ws_host_service_stats.rs):
async fn replay_stats_history(
socket: &mut WebSocket,
history: &Mutex<HashMap<String, VecDeque<serde_json::Value>>>,
key: &str,
) -> ControlFlow<()>
4. Extract broadcast forwarding loop
The tokio::select! loop in handle_stats_socket that forwards broadcast messages to the socket. Shared across all three stats handlers. Extract into a common module if possible:
async fn relay_broadcast_to_socket(
socket: &mut WebSocket,
rx: &mut broadcast::Receiver<serde_json::Value>,
key: &str,
)
5. Add unit tests
poll_service_stats and broadcast/history helpers are hard to unit test without mocks. Focus on:
- Any pure helpers that come out of extraction (JSON parsing, key construction, etc.)
Important
The workspace Cargo.toml sets cognitive_complexity, too_many_lines, too_many_arguments, and several other clippy lints to warn globally. Run make lint after every change and make sure the output is clean. Don't fix a suppression here only to create new warnings elsewhere.
Acceptance criteria
Related
Tracking issue pattern from previous PRs: #122, #133, #157, #158, #171, #172, #173, #174, #175
ws_service_stats.rshas two suppressions:run_service_collector(line 254) andhandle_stats_socket(line 436), both#[allow(clippy::cognitive_complexity)].What they do
run_service_collector(~90 lines) — resolves the inner container for a service, then pollsdocker stats --no-streamevery 2 seconds in a loop, parses JSON, pushes to history ring, broadcasts to subscribershandle_stats_socket(~55 lines) — replays history buffer to a newly connected WebSocket client, then runs atokio::select!loop relaying broadcast receiver output to the socket (same pattern asws_stats.rsandws_host_service_stats.rs)What to do
1. Extract single-poll execution in
run_service_collectorLines 290–323 build exec options, run
create_exec+start_exec, accumulate stdout, and parse JSON. Extract:2. Extract history push + broadcast
Lines 325–335 push the new value into the history ring and send to the broadcast channel. Extract (could be shared with
ws_host_service_stats.rsandws_stats.rs):3. Extract history replay for
handle_stats_socketLines 440+ replay the history ring to the socket. Extract (shared with
ws_stats.rsandws_host_service_stats.rs):4. Extract broadcast forwarding loop
The
tokio::select!loop inhandle_stats_socketthat forwards broadcast messages to the socket. Shared across all three stats handlers. Extract into a common module if possible:5. Add unit tests
poll_service_statsand broadcast/history helpers are hard to unit test without mocks. Focus on:Important
The workspace
Cargo.tomlsetscognitive_complexity,too_many_lines,too_many_arguments, and several other clippy lints towarnglobally. Runmake lintafter every change and make sure the output is clean. Don't fix a suppression here only to create new warnings elsewhere.Acceptance criteria
poll_service_statsextracted (fromrun_service_collector)push_stats_to_history_and_broadcastextracted (shared if possible)replay_stats_historyextracted (shared with other stats handlers)relay_broadcast_to_socketextracted (shared)make test)make lintpasses with zero new warnings#[allow(clippy::cognitive_complexity)]suppressions ifmake lintpasses without them, keep any still needed (note why)Related
Tracking issue pattern from previous PRs: #122, #133, #157, #158, #171, #172, #173, #174, #175