obzenflow_runtime 0.2.4

Runtime services for ObzenFlow - execution and coordination business logic
Documentation
// SPDX-License-Identifier: MIT OR Apache-2.0
// SPDX-FileCopyrightText: 2025-2026 ObzenFlow Contributors
// https://obzenflow.dev

//! Unified subscription polling trait for FSM-controlled event consumption
//!
//! This trait provides a consistent polling interface for all subscription types,
//! ensuring that FSMs control sleep timing and preventing busy loops.

use obzenflow_core::event::JournalEvent;
use obzenflow_core::{JournalRecord, StageId};
use std::fmt::Debug;

/// Result of polling a subscription for events
#[derive(Debug)]
// Keep the delivered record inline, preserving the existing allocation-free poll handoff.
#[allow(clippy::large_enum_variant)]
pub enum PollResult<T: JournalEvent> {
    /// An event is available
    Event(JournalRecord<T::Payload>),

    /// The journal cursor advanced across a transport-filtered row.
    ///
    /// `completed_data_rows` is physical transport accounting. It deliberately
    /// does not imply a logical delivery, input position, receipt, or contract
    /// update. Returning it as a poll outcome bounds filtered-row work and lets
    /// the owning FSM replenish the matching physical edge directly.
    CursorAdvanced {
        upstream: StageId,
        completed_data_rows: u64,
    },

    /// No events currently available (would block)
    NoEvents,

    /// Error occurred while polling
    Error(Box<dyn std::error::Error + Send + Sync>),
}

/// Trait for non-blocking subscription polling
///
/// This trait unifies the polling interface for different subscription types,
/// ensuring consistent behavior across the system:
/// - Non-blocking polling (returns immediately)
/// - Clear semantics for each result variant
/// - FSM controls all sleep/retry timing
#[async_trait::async_trait]
pub trait SubscriptionPoller: Send + Sync {
    /// The type of events this subscription produces
    type Event: JournalEvent;

    /// Poll for the next event without blocking
    ///
    /// Returns immediately with one of:
    /// - `Event`: An event is ready
    /// - `CursorAdvanced`: a filtered row was consumed
    /// - `NoEvents`: No events available right now
    /// - `Error`: An error occurred
    async fn poll_next(&mut self) -> PollResult<Self::Event>;

    /// Get the name/identifier of this subscription for logging
    fn name(&self) -> &str;
}