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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! In-process pub/sub wiring (RFC-023 §4.2).
//!
//! Phase 2b.1 wires the five broadcast-channel outboxes (Group D.1).
//! Each channel corresponds to one outbox table; subscribers (Phase
//! 2b.2 / later) hold a `Receiver` and wake on post-commit emits.
//!
//! # Ordering / durability invariant (RFC-023 §4.2 A2)
//!
//! The broadcast channel is **wakeup only** — not the durable
//! record of what happened. Events land as rows on the matching
//! outbox table **inside** the writing transaction; the
//! `emit_post_commit` helper fires AFTER `tx.commit()` returns, with
//! the row(s) just committed as the payload. A late subscriber that
//! missed a broadcast tick can still recover every event by tailing
//! the outbox table `WHERE event_id > cursor`. That is the RFC-019
//! cursor-resume contract.
//!
//! # Partition routing
//!
//! Each [`OutboxEvent`] carries the partition key it landed on; a
//! partition-scoped subscriber filters on its own `OutboxEvent::partition_key`.
//! The post-commit emit is wakeup-only and does not determine
//! durability. If broadcast `send` finds no attached receivers it
//! returns `Err(SendError(_))`; we intentionally ignore that case
//! because durable replay comes from the outbox table, so a missed
//! wakeup is NOT a lost event from the producer's POV.
use broadcast;
/// Capacity of each broadcast channel's ring buffer. Tuned conservatively
/// for the dev-only single-writer envelope; late subscribers catch up via
/// the outbox table, so lost-wakeup only means an extra outbox poll on
/// the catch-up side (not a lost event).
const DEFAULT_CAPACITY: usize = 256;
/// One wakeup broadcast payload, one per outbox row written.
///
/// Carries enough identification for a subscriber to filter on its
/// partition / execution of interest without re-reading the outbox
/// row. The full row (including any non-identifying payload columns
/// — e.g. `outcome`, `event_type`, `details`) is fetched by the
/// subscriber from the outbox table using `event_id` as a cursor,
/// matching the RFC-019 catch-up shape.
// test-only surface exposed via `subscribe_*_for_test`
/// Per-backend in-process wakeup channels. One broadcast channel per
/// outbox family; each `Sender` is held on `SqliteBackendInner` and
/// subscribers derive `Receiver` handles via `Sender::subscribe()`
/// (Phase 2b.2+).
pub