commit a6b624d4d81ab2c9bcf962d3a33d86597f21c1dc
parent 661c8fe4f887997e59fd413312535532c39fc35f
Author: triesap <tyson@radroots.org>
Date: Wed, 17 Jun 2026 14:17:16 -0700
outbox: expose failed terminal status counts
- add failed terminal event counts to outbox status summaries
- keep SDK storage/readiness status from treating all terminal states alike
- validate with rr-rs fmt, event-store/outbox tests, and nix flake check
Diffstat:
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/crates/outbox/src/model.rs b/crates/outbox/src/model.rs
@@ -280,6 +280,7 @@ pub struct RadrootsOutboxStatusSummary {
pub pending_events: i64,
pub retryable_events: i64,
pub terminal_events: i64,
+ pub failed_terminal_events: i64,
pub ready_signed_events: i64,
pub publishing_events: i64,
pub last_attempt_at_ms: Option<i64>,
diff --git a/crates/outbox/src/store.rs b/crates/outbox/src/store.rs
@@ -76,7 +76,7 @@ impl RadrootsOutbox {
now_ms: i64,
) -> Result<RadrootsOutboxStatusSummary, RadrootsOutboxError> {
let row = sqlx::query(
- "SELECT COUNT(*) AS total_events, COALESCE(SUM(CASE WHEN state IN ('draft_queued', 'signing', 'signed', 'publishing') THEN 1 ELSE 0 END), 0) AS pending_events, COALESCE(SUM(CASE WHEN state IN ('sign_retryable', 'publish_retryable') THEN 1 ELSE 0 END), 0) AS retryable_events, COALESCE(SUM(CASE WHEN state IN ('published', 'failed_terminal', 'cancelled') THEN 1 ELSE 0 END), 0) AS terminal_events, COALESCE(SUM(CASE WHEN state = 'publishing' THEN 1 ELSE 0 END), 0) AS publishing_events FROM outbox_event",
+ "SELECT COUNT(*) AS total_events, COALESCE(SUM(CASE WHEN state IN ('draft_queued', 'signing', 'signed', 'publishing') THEN 1 ELSE 0 END), 0) AS pending_events, COALESCE(SUM(CASE WHEN state IN ('sign_retryable', 'publish_retryable') THEN 1 ELSE 0 END), 0) AS retryable_events, COALESCE(SUM(CASE WHEN state IN ('published', 'failed_terminal', 'cancelled') THEN 1 ELSE 0 END), 0) AS terminal_events, COALESCE(SUM(CASE WHEN state = 'failed_terminal' THEN 1 ELSE 0 END), 0) AS failed_terminal_events, COALESCE(SUM(CASE WHEN state = 'publishing' THEN 1 ELSE 0 END), 0) AS publishing_events FROM outbox_event",
)
.fetch_one(&self.pool)
.await?;
@@ -105,6 +105,7 @@ impl RadrootsOutbox {
pending_events: row.try_get("pending_events")?,
retryable_events: row.try_get("retryable_events")?,
terminal_events: row.try_get("terminal_events")?,
+ failed_terminal_events: row.try_get("failed_terminal_events")?,
ready_signed_events,
publishing_events: row.try_get("publishing_events")?,
last_attempt_at_ms,
@@ -1342,6 +1343,7 @@ mod tests {
assert_eq!(empty.pending_events, 0);
assert_eq!(empty.retryable_events, 0);
assert_eq!(empty.terminal_events, 0);
+ assert_eq!(empty.failed_terminal_events, 0);
assert_eq!(empty.ready_signed_events, 0);
assert_eq!(empty.publishing_events, 0);
assert_eq!(empty.last_attempt_at_ms, None);
@@ -1402,6 +1404,7 @@ mod tests {
assert_eq!(retry_wait.pending_events, 0);
assert_eq!(retry_wait.retryable_events, 1);
assert_eq!(retry_wait.terminal_events, 0);
+ assert_eq!(retry_wait.failed_terminal_events, 0);
assert_eq!(retry_wait.ready_signed_events, 0);
assert_eq!(retry_wait.last_attempt_at_ms, Some(2_100));
assert_eq!(