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
//! # Duroxide PostgreSQL Provider
//!
//! A PostgreSQL-based provider implementation for [Duroxide](https://crates.io/crates/duroxide),
//! a durable task orchestration framework for Rust.
//!
//! ## Usage
//!
//! ```rust,no_run
//! use duroxide_pg_opt::PostgresProvider;
//! use duroxide::runtime::Runtime;
//! use std::sync::Arc;
//!
//! # async fn example() -> anyhow::Result<()> {
//! // Create a provider with the database URL
//! let provider = PostgresProvider::new("postgres://user:password@localhost:5432/mydb").await?;
//!
//! // Use with the Duroxide runtime
//! // let runtime = Runtime::start_with_store(Arc::new(provider), activity_registry, orchestration_registry).await;
//! # Ok(())
//! # }
//! ```
//!
//! ## Custom Schema
//!
//! To isolate data in a specific PostgreSQL schema (useful for multi-tenant deployments):
//!
//! ```rust,no_run
//! use duroxide_pg_opt::PostgresProvider;
//!
//! # async fn example() -> anyhow::Result<()> {
//! let provider = PostgresProvider::new_with_schema(
//! "postgres://user:password@localhost:5432/mydb",
//! Some("my_schema"),
//! ).await?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Configuration
//!
//! | Environment Variable | Description | Default |
//! |---------------------|-------------|---------|
//! | `DUROXIDE_PG_POOL_MAX` | Maximum connection pool size | `10` |
//!
//! ## Long-Polling
//!
//! The provider supports long-polling via PostgreSQL LISTEN/NOTIFY to reduce idle query load:
//!
//! ```rust,no_run
//! use duroxide_pg_opt::{PostgresProvider, LongPollConfig};
//! use std::time::Duration;
//!
//! # async fn example() -> anyhow::Result<()> {
//! let config = LongPollConfig {
//! enabled: true,
//! notifier_poll_interval: Duration::from_secs(60),
//! timer_grace_period: Duration::from_millis(100),
//! };
//!
//! let provider = PostgresProvider::new_with_options(
//! "postgres://user:password@localhost:5432/mydb",
//! Some("my_schema"),
//! config,
//! ).await?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Features
//!
//! - Automatic schema migration on startup
//! - Connection pooling via sqlx
//! - Custom schema support for multi-tenant isolation
//! - Long-polling via LISTEN/NOTIFY for reduced database load
//! - Full implementation of the Duroxide `Provider` and `ProviderAdmin` traits
//!
//! ## Fault Injection (Testing)
//!
//! For testing resilience scenarios, enable the `test-fault-injection` feature:
//!
//! ```toml
//! [dev-dependencies]
//! duroxide-pg = { version = "0.1", features = ["test-fault-injection"] }
//! ```
///
/// ## Database Metrics (Instrumentation)
///
/// For database operation instrumentation, enable the `db-metrics` feature:
///
/// ```toml
/// [dependencies]
/// duroxide-pg = { version = "0.1", features = ["db-metrics"] }
/// ```
///
/// This enables zero-cost metrics collection for all database operations.
/// See the [`db_metrics`] module for details.
pub use FaultInjector;
pub use LongPollConfig;
pub use PostgresProvider;