harmont_cli/orchestrator/output_subscriber.rs
1//! Build-event subscriber that passes events to an [`OutputRenderer`].
2//!
3//! Replaces the plan-2 plugin-based output subscriber with a simple
4//! loop that calls [`OutputRenderer::on_event`] for each bus event.
5
6// Pedantic-bucket nags accepted at module scope:
7// - `needless_pass_by_value` on `bus`: the owned `Arc<EventBus>` makes
8// the bus->subscriber handoff explicit at the call site.
9#![allow(clippy::needless_pass_by_value)]
10
11use std::sync::Arc;
12
13use tokio::sync::broadcast::error::RecvError;
14
15use super::events::EventBus;
16use crate::runner::OutputRenderer;
17
18/// Spawn the subscriber task. Returns a join handle the orchestrator
19/// awaits at shutdown so the `BuildEnd` event is fully drained.
20#[must_use]
21pub fn spawn(
22 bus: Arc<EventBus>,
23 mut renderer: Box<dyn OutputRenderer>,
24) -> tokio::task::JoinHandle<()> {
25 let mut rx = bus.subscribe();
26 tokio::spawn(async move {
27 loop {
28 match rx.recv().await {
29 Ok(event) => {
30 let is_end = event.is_build_end();
31 renderer.on_event(&event);
32 if is_end {
33 return;
34 }
35 }
36 Err(RecvError::Closed) => return,
37 Err(RecvError::Lagged(n)) => {
38 tracing::warn!("output: dropped {n} events");
39 }
40 }
41 }
42 })
43}