- Rust 58.8%
- PLpgSQL 36.9%
- Shell 3.4%
- Python 0.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Prepare duroxide-pg 0.1.38 with the lock-safety fixes from #44 and migration 0026 upgrade notes. Package publication remains a separate maintainer operation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f0e4a2b7-cb07-472c-8af1-62da8abd5a63 |
||
| .agents/skills | ||
| .github | ||
| docs | ||
| logs | ||
| migrations | ||
| pg-stress | ||
| prompts | ||
| scripts | ||
| src | ||
| tests | ||
| .env.example | ||
| .gitignore | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| CODE_OF_CONDUCT.md | ||
| CONTRIBUTING.md | ||
| LICENSE | ||
| README.md | ||
| RELEASE_POLICY.md | ||
| rust-toolchain.toml | ||
| SECURITY.md | ||
| STRESS_TEST_SUMMARY.md | ||
| TODO.md | ||
Duroxide PostgreSQL Provider
A PostgreSQL-based provider implementation for Duroxide, a durable task orchestration framework for Rust.
Looking for durable functions directly in SQL? That's pg_durable — a PostgreSQL extension built on top of duroxide + duroxide-pg. duroxide-pg itself is the lower-level Rust building block: use it when you want to author your own workflows in Rust against a Postgres-backed store.
Note: See CHANGELOG.md for version history and breaking changes.
Installation
Add to your Cargo.toml:
[dependencies]
duroxide-pg = "0.1"
Usage
use duroxide_pg::PostgresProvider;
use duroxide::Worker;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Create a provider with the database URL
let provider = PostgresProvider::new("postgres://user:password@localhost:5432/mydb").await?;
// Use with a Duroxide worker
let worker = Worker::new(provider);
// ... register orchestrations and activities, then run
Ok(())
}
Custom Schema
To isolate data in a specific PostgreSQL schema:
let provider = PostgresProvider::new_with_schema(
"postgres://user:password@localhost:5432/mydb",
Some("my_schema"),
).await?;
Microsoft Entra ID Authentication (Azure Database for PostgreSQL)
Connect to Azure Database for PostgreSQL Flexible Server using a Microsoft
Entra ID (Azure AD) access token instead of a static password. The provider
acquires the initial token at construction time and a background task
refreshes it before expiry, swapping the new token into the pool via
sqlx::Pool::set_connect_options.
use duroxide_pg::{EntraAuthOptions, PostgresProvider};
# async fn example() -> anyhow::Result<()> {
let provider = PostgresProvider::new_with_entra(
"myserver.postgres.database.azure.com",
5432,
"mydb",
"my-entra-principal@contoso.onmicrosoft.com",
EntraAuthOptions::new(),
)
.await?;
# Ok(()) }
For multi-tenant deployments use the schema variant:
use duroxide_pg::{EntraAuthOptions, PostgresProvider};
# async fn example() -> anyhow::Result<()> {
let provider = PostgresProvider::new_with_schema_and_entra(
"myserver.postgres.database.azure.com",
5432,
"mydb",
"my-entra-principal@contoso.onmicrosoft.com",
Some("tenant_a"),
EntraAuthOptions::new(),
)
.await?;
# Ok(()) }
Identity sources
By default the provider chains [WorkloadIdentityCredential (only when AKS federated env vars are present), ManagedIdentityCredential, DeveloperToolsCredential] — so the same code works for:
- AKS: Workload Identity federation (preferred when
AZURE_FEDERATED_TOKEN_FILEand friends are set). - Production: User-assigned or system-assigned managed identity, App Service / Container Apps managed identity.
- Local dev:
az login(Azure CLI) orazd auth login.
Required Azure setup
- Configure an Entra admin on the Flexible Server (
az postgres flexible-server ad-admin set). - Create a Postgres role for the principal:
SELECT pgaadauth_create_principal('my-app-managed-identity', false, false); - Grant the role the privileges your application needs (
GRANT ... ON DATABASE ...,GRANT USAGE ON SCHEMA ..., etc.).
Sovereign clouds
The default audience is the public-cloud value
https://ossrdbms-aad.database.windows.net/.default. Override for sovereign
clouds:
use std::time::Duration;
use duroxide_pg::EntraAuthOptions;
let options = EntraAuthOptions::new()
.audience("https://ossrdbms-aad.database.usgovcloudapi.net/.default")
.refresh_interval(Duration::from_secs(15 * 60));
Notes
- All Entra connections are pinned to
PgSslMode::VerifyFull. There is no fallback to weaker TLS modes. - Brief auth-failure windows during token rotation surface as retryable
ProviderErrors (SQLSTATE28000/28P01) so the runtime retries transparently. - See the Entra ID technical reference for the design rationale (refresh scheduling, troubleshooting, dependency choices).
Testing
Two test layers cover the Entra integration:
-
Local pipeline tests (
cargo test --lib entra_pipeline) — exercise the full token → connect-options → pool → migrations flow against a local PostgreSQL by injecting a fakeTokenSource(no Azure dependency). They automatically skip ifDATABASE_URLis not set. -
Live Entra smoke test (
tests/entra_live_test.rs,#[ignore]) — opt in by settingDUROXIDE_PG_ENTRA_LIVE_TEST=1plusDUROXIDE_PG_ENTRA_TEST_HOST,DUROXIDE_PG_ENTRA_TEST_DB, andDUROXIDE_PG_ENTRA_TEST_USER. Run withcargo test --test entra_live_test -- --ignored. Credentials are picked up from the ambientazure_identitychain.First-time setup. A pair of helper scripts provisions an ephemeral Azure Database for PostgreSQL Flexible Server (Burstable B1ms tier, ~$13/month if left running — remember to tear it down):
az login ./scripts/provision_entra_test_pg.sh # creates RG + server + firewall + Entra admin # (script prints the env-var block to copy into your shell) cargo test --test entra_live_test -- --ignored --nocapture ./scripts/teardown_entra_test_pg.sh # deletes the resource groupThe scripts are idempotent and use the currently
az login'd user as the Entra admin / test principal. Override naming withDUROXIDE_PG_ENTRA_TEST_PREFIX,DUROXIDE_PG_ENTRA_TEST_LOCATION,DUROXIDE_PG_ENTRA_TEST_RG, orDUROXIDE_PG_ENTRA_TEST_SERVERenv vars (see the script headers for details).
Configuration
| Environment Variable | Description | Default |
|---|---|---|
DUROXIDE_PG_POOL_MAX |
Maximum connection pool size | 10 |
Features
- Automatic schema migration on startup
- Connection pooling via sqlx
- Custom schema support for multi-tenant isolation
- Full implementation of the Duroxide
ProviderandProviderAdmintraits - Poison message detection with attempt count tracking
- Lock renewal for long-running orchestrations and activities
- KV store — durable per-instance key-value state for orchestration coordination
- Orchestration stats introspection via
Client::get_orchestration_stats() - Microsoft Entra ID authentication for Azure Database for PostgreSQL (managed identity, Workload Identity, az CLI)
Latest Release (0.1.38)
- Fixes an orchestration acknowledge that could commit after another worker had taken the instance over. The consumed messages stayed queued and were processed again, so one queue message or external event could run an activity twice (migration
0026). - Fixes deadlocks between orchestration lock renewal and fetch, acknowledge or abandon, and stops renewal from reviving an expired lease or shortening a live one (migration
0026). - Retries transient renewal errors, and finds leases by lock token through a new unique index instead of a table scan.
- Adds a deadlock test suite that runs in every
cargo test, and a TLA+ model of the lease procedures under worker clock skew (docs/tla/orchestration-leases). - See CHANGELOG.md for full version history.
Releases are published by Microsoft's internal OSS infrastructure. See RELEASE_POLICY.md for details.
Previous Release (0.1.37)
- Fails startup on catalog errors, inconsistent migration history, or missing, unexpected, or non-table Duroxide relations without deleting migration records or re-applying old SQL.
- Reports malformed KV snapshots through
history_error, allowing the runtime to poison the instance aftermax_attemptsinstead of replaying an empty snapshot or retrying forever. - Keeps malformed durable history out of orphan-message cleanup so its queue messages are not acknowledged before runtime poison/backoff handling.
Support
Use GitHub Issues for bug reports and feature requests. Do not report security vulnerabilities through public GitHub issues; follow the instructions in SECURITY.md instead.
Code of Conduct
This project has adopted the Microsoft Open Source Code of Conduct. For more information, see the Code of Conduct FAQ or contact opencode@microsoft.com with questions or comments.
Security
Microsoft takes the security of our software products and services seriously. Please do not report security vulnerabilities through public GitHub issues. See SECURITY.md for security reporting instructions.
Privacy and Telemetry
duroxide-pg does not send telemetry to Microsoft. Applications may configure their own database, logging, or metrics collection; those signals are controlled by the application owner.
Trademarks
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos is subject to those third-party policies.
License
MIT License - see LICENSE for details.