Skip to main content

outbox_core/
publisher.rs

1//! Publishing abstraction between the outbox worker and the external broker.
2//!
3//! [`Transport`] is the narrow boundary an implementation crate (such as
4//! `outbox-kafka` or `outbox-rabbit`) has to satisfy for
5//! [`OutboxManager`](crate::manager::OutboxManager) to deliver events to a
6//! message bus.
7
8use crate::error::OutboxError;
9use crate::model::Event;
10use std::fmt::Debug;
11
12/// Publishes a single [`Event`] to an external system.
13///
14/// Implementations are expected to be self-contained — everything the
15/// transport needs (connection pool, topic mapping, serializer) should live
16/// inside the `impl` so that the worker can keep its loop simple and focused
17/// on orchestration.
18///
19/// Implementations must be `Send + Sync` because the manager holds them
20/// behind an `Arc` and may drive them from arbitrary tokio tasks.
21#[cfg_attr(test, mockall::automock)]
22#[async_trait::async_trait]
23pub trait Transport<P>: Send + Sync
24where
25    P: Debug + Clone + Send + Sync,
26{
27    /// Sends an event to an external system.
28    ///
29    /// Called per-event by [`OutboxProcessor`](crate::processor::OutboxProcessor).
30    /// A successful return means the broker has accepted responsibility for
31    /// the message; any retry semantics beyond that are an implementation
32    /// detail of the concrete transport.
33    ///
34    /// # Errors
35    ///
36    /// Returns an [`OutboxError`] — usually
37    /// [`BrokerError`](OutboxError::BrokerError) — if the broker call fails.
38    /// The manager treats this as a per-event failure: the event is left in
39    /// the processing state (and will be retried when its lock expires or, if
40    /// the `dlq` feature is on, tracked via the DLQ heap) while sibling
41    /// events in the same batch are still processed.
42    async fn publish(&self, event: Event<P>) -> Result<(), OutboxError>;
43}