//! Opening the hive-notices stream a hive publishes lifecycle notices into. The //! stream name, subject shape and why it is a stream rather than a bucket are in //! `swarm_wire::notices`. //! //! Feature-gated (`notices`) so the crate's other consumers do not compile //! against a stream shape they never touch. use crate::Error; use swarm_wire::notices::STREAM; /// Open the notices stream, creating it if nothing has yet. /// /// **Retention is time-bounded (30 days), not unbounded.** A notice /// this old has long since been superseded by whatever the hive is /// doing now — keeping it forever buys nothing but disk, the same /// argument `hive-forge`'s own bash-task retention makes elsewhere in /// this workspace. /// /// Creating rather than requiring a provisioning step is the same call /// [`crate::status::open_or_create`] makes and for the same reason: a /// hive and a swarm-level consumer come up in no particular order, and /// a stream that must pre-exist turns "deployed in the wrong order" /// into a permanent, silent absence of data. pub async fn open_or_create( client: &async_nats::Client, ) -> Result { let js = async_nats::jetstream::new(client.clone()); match js.get_stream(STREAM).await { Ok(stream) => Ok(stream), Err(e) => { tracing::info!( stream = STREAM, reason = %e, "notices stream not available, creating it" ); js.create_stream(async_nats::jetstream::stream::Config { name: STREAM.to_owned(), description: Some("Lifecycle notices offered by each hive".to_owned()), subjects: vec![format!("{STREAM}.>")], max_age: std::time::Duration::from_hours(30 * 24), ..Default::default() }) .await .map_err(|source| Error::CreateStream { stream: STREAM, source, }) } } }