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}