1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//! The `Publisher` trait and `PublishError` enum — Phase 5 Task 11.5.
//!
//! Any struct that can deliver an outbox row to a downstream transport
//! implements `Publisher`. The framework ships one built-in implementation
//! ([`NotifyPublisher`](super::publishers::notify::NotifyPublisher)) that uses
//! Postgres `NOTIFY` with zero extra dependencies.
//!
//! # Object safety
//!
//! `Publisher` is designed to be stored as `Box<dyn Publisher>` or
//! `Arc<dyn Publisher>`. The `#[async_trait::async_trait]` attribute rewrites
//! the `async fn publish` body so the trait is object-safe.
//!
//! # Error variants
//!
//! `PublishError` carries a `Transient` / `Permanent` distinction so the relay
//! loop can decide whether to retry:
//!
//! - [`PublishError::Transient`] — downstream hiccup (network timeout, rate
//! limit, broker restart). Pass `retryable = true` to `mark_failed`.
//! - [`PublishError::Permanent`] — payload too large, schema violation, unknown
//! channel. Pass `retryable = false` to `mark_failed`.
//! - [`PublishError::Provider`] — wraps an underlying provider error where the
//! transience is unknown; the relay should treat this as transient by default.
use OutboxRow;
use async_trait;
/// Deliver a single outbox row to a downstream transport.
///
/// Implementations must be `Send + Sync + 'static` so they can be stored in a
/// `Box<dyn Publisher>` and shared across Tokio tasks.
///
/// # Error semantics
///
/// - Return `Ok(())` only after the transport has durably accepted the message
/// (or the implementation is fire-and-forget by design).
/// - Return `Err(PublishError::Transient { .. })` for retriable failures so the
/// relay can call `mark_failed(retryable = true)` and try again later.
/// - Return `Err(PublishError::Permanent { .. })` for terminal failures so the
/// relay can call `mark_failed(retryable = false)`.
/// Failure mode for a single publish attempt.
///
/// The relay loop inspects this to decide whether to retry via
/// `mark_failed(retryable = true/false)`.