hyperi_rustlib/dlq/mod.rs
1// Project: hyperi-rustlib
2// File: src/dlq/mod.rs
3// Purpose: Unified dead letter queue with pluggable backends
4// Language: Rust
5//
6// License: BUSL-1.1
7// Copyright: (c) 2026 HYPERI PTY LIMITED
8
9//! Unified dead letter queue (DLQ) with pluggable backends.
10//!
11//! Provides a shared DLQ abstraction for all DFE services. Failed messages
12//! are routed to one or more backends (file, Kafka, or custom) using
13//! configurable cascade or fan-out modes.
14//!
15//! ## Backends
16//!
17//! - **File**: NDJSON files with automatic rotation and cleanup. Always
18//! available, no external dependencies.
19//! - **Kafka**: Routes to Kafka topics with per-table or common
20//! routing. Requires the `dlq-kafka` feature.
21//! - **HTTP**: POSTs entries as NDJSON. Requires the `dlq-http` feature.
22//! - **Redis**: XADDs entries to a Redis Stream. Requires the
23//! `dlq-redis` feature.
24//!
25//! Backends are selected and configured via [`DlqConfig`]; consumers
26//! never construct backend types directly. To add a new backend, extend
27//! the [`DlqBackend`] enum in rustlib itself.
28//!
29//! ## Modes
30//!
31//! - **Cascade** (default): Try backends in order, stop on first success.
32//! - **Fan-out**: Write to all backends, succeed if any succeed.
33//! - **FileOnly**: File backend only (no Kafka dependency).
34//! - **KafkaOnly**: Kafka backend only.
35//!
36//! ## Example
37//!
38//! ```rust,no_run
39//! use hyperi_rustlib::dlq::{Dlq, DlqConfig, DlqEntry, DlqSource};
40//! use tokio_util::sync::CancellationToken;
41//!
42//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
43//! let config = DlqConfig::default();
44//! let shutdown = CancellationToken::new();
45//! let dlq = Dlq::spawn(&config, "my-service", None, shutdown.clone())?;
46//!
47//! let entry = DlqEntry::new("my-service", "parse_error", b"bad data".to_vec())
48//! .with_destination("acme.auth")
49//! .with_source(DlqSource::kafka("events", 1, 42));
50//!
51//! dlq.send(entry).await?; // queued (non-blocking)
52//! dlq.flush().await?; // wait for durable write
53//! shutdown.cancel();
54//! dlq.shutdown().await?; // drain + exit
55//! # Ok(())
56//! # }
57//! ```
58
59mod backend;
60mod config;
61mod entry;
62mod error;
63mod file;
64mod orchestrator;
65
66#[cfg(feature = "dlq-kafka")]
67mod kafka;
68
69#[cfg(feature = "dlq-http")]
70mod http;
71
72#[cfg(feature = "dlq-redis")]
73mod redis_dlq;
74
75// Core types (always available with `dlq` feature)
76pub use backend::DlqBackend;
77pub use config::{DlqConfig, DlqMode, FileDlqConfig, RotationPeriod};
78pub use entry::{DlqEntry, DlqSource};
79pub use error::DlqError;
80pub use orchestrator::Dlq;
81
82// Kafka types (only with `dlq-kafka` feature)
83#[cfg(feature = "dlq-kafka")]
84pub use config::{DlqRouting, KafkaDlqConfig};
85
86// HTTP types (only with `dlq-http` feature)
87#[cfg(feature = "dlq-http")]
88pub use http::HttpDlqConfig;
89
90// Redis types (only with `dlq-redis` feature)
91#[cfg(feature = "dlq-redis")]
92pub use redis_dlq::RedisDlqConfig;
93
94/// Result type for DLQ operations.
95pub type Result<T> = std::result::Result<T, DlqError>;