Skip to content

Repository files navigation

batter

A cohesive facade for a native operational foundation built on Tokio, with separate Axum, SQLx, Runledger, and Runlimit adapters. Keep your normal futures, application error enums, SQLx pools, transactions, and routers. Standardize how work is owned, bounded, observed, and stopped—not how every business operation is written.

It is for Tokio services that need owned shutdown, deadlines, and cleanup. It is not a web framework, DI container, or a replacement for application types.

For coding-agent consumers

Batter's integration APIs are designed for autonomous coding agents. Prefer the canonical, library-driven path so operational invariants follow from ownership, constrained interfaces, validated configuration, and executable checks. Repeated caller obligations to coordinate cancellation, joining, cleanup, deadline relationships, registration, or error retention are design debt, even when documented. Keep application-specific protocols in the application or a supported adapter; agent-only consumption does not call for an opaque DSL, extra abstraction layers, or claims that types prove arbitrary remote effects.

Examples are consumer contracts. When a lower-level escape hatch is necessary, its documentation must state the obligations it leaves with the caller and must not present it as equivalent to the protected path. Assess proposed changes with independent failure scenarios and fresh-agent implementation or modification tasks; clean reviews or test volume alone do not establish agent usability. Those evaluations are proposed and unexecuted unless this repository records specific evidence. See ADR-010, architecture, and usage.

Recurring invariant failures during example review require the implementation agent to assess the consumed API and report the design concern before continuing dependent repairs.

Status

Version 0.1.0. Publishing is disabled; no registry name has been reserved. Linux x86_64 and macOS arm64 have execution evidence on Rust 1.94.0 and 1.98.1. The updated macOS CI job has not run. See current status.

Platform support

Batter targets Unix backends, including Linux and macOS. Windows is unsupported, and there are no plans to support it. This applies to all workspace packages, examples, tests and tooling. There are no Windows implementation branches or CI targets. Other Unix targets remain unverified. See ADR-007.

Quick start

Network access is required to download dependencies on the first run.

cargo run -p batter --features axum --example http_service
# In a second terminal:
curl -i http://127.0.0.1:3000/live
curl -i http://127.0.0.1:3000/ready
curl -i http://127.0.0.1:3000/work

BATTER_BIND defaults to 127.0.0.1:3000; BATTER_REQUEST_TIMEOUT_MS defaults to 2000; BATTER_BULKHEAD_CAPACITY defaults to 32. BATTER_ENV_FILE may name one literal dotenv file; there is no default .env search. Invalid values fail before bind. See operations. This is an integration example, not a business API: /work simulates a 25 ms read under a concurrency bound, and /fail uses the same application error envelope as middleware failures. SIGINT and SIGTERM trigger shutdown through native Unix signal listeners.

Bound an operation without erasing its application error

use batter::operation::OperationContext;
use std::time::Duration;

async fn read_count() -> Result<u64, std::io::Error> {
    Ok(42) // Replace with your dependency; preserve its concrete error type.
}

async fn example() -> Result<(), Box<dyn std::error::Error>> {
    let request = OperationContext::new(Duration::from_secs(2))?;
    let count = request.run("accounts.count", |_scope| read_count()).await?;
    assert_eq!(count, 42);
    Ok(())
}

run receives a factory, creates a child context, and cancels that child when execution completes or its future is dropped. It does not join tasks spawned by the callback. Compose request-local futures normally; do not turn them into unowned tokio::spawn calls. See usage for retries and ownership.

Other examples

cargo run -p batter --example worker
cargo run -p batter --example process_owned
cargo run -p batter --example operation_budget
cargo run -p batter --example finite_command
DATABASE_URL='postgres://user:password@localhost/database' \
  cargo run -p batter-example-postgres-lifecycle --bin postgres_lifecycle

The PostgreSQL example connects to an existing database, probes it with SELECT 1, demonstrates partial-startup cleanup, and registers native pool closure. It does not create/drop databases or migrate a Runledger schema. Use only a local test database; never commit real connection secrets.

finite_command uses command::Command to own one native loopback operation and retain cleanup independently of its waiter. Service startup is a different ownership path; see usage and the executable Startup example.

Use as a local dependency

Path dependencies only. Every workspace package is publish = false. The toml below assumes this repository is checked out as batter beside the consumer:

[dependencies]
# Public facade; its default graph contains only the native foundation.
batter = { path = "../batter/crates/batter" }
# Select optional toolkit namespaces explicitly, for example:
# batter = { path = "../batter/crates/batter", features = ["axum"] }
# Direct foundation implementation, when an adapter or focused consumer needs it.
batter-core = { path = "../batter/crates/batter-core" }
# Add this dependency for the HTTP adapter.
batter-axum = { path = "../batter/crates/batter-axum" }
# Add for explicit SQLx PostgreSQL connection disposition.
batter-sqlx = { path = "../batter/crates/batter-sqlx" }

[dev-dependencies]
batter-test-support = { path = "../batter/crates/batter-test-support" }

Packages

The default batter graph does not bring in Axum, SQLx, or test utilities. Adapter APIs are also available from their direct packages. The facade exposes batter::axum, batter::sqlx, batter::runledger, batter::runlimit, and batter::test_support through additive opt-in features; runlimit-memory, runlimit-postgres, runlimit-axum, and sqlx-test-support select only their documented bridges. Each package declares its own version and Rust minimum (currently 0.1.0 and 1.94). The default toolchain is 1.98.1. SQLx 0.9.0 sets that floor in the adapter and examples; extracting it does not establish a lower library minimum.

Package Location Job
batter crates/batter Source-compatible public facade and runnable foundation consumers.
batter-core crates/batter-core Single native implementation for process ownership, deadlines, retry, admission, cleanup, health/readiness, startup, settings, and telemetry.
batter-axum crates/batter-axum HTTP adapter: request policy, observation, correlation, readiness, browser credential transport, and native serving.
batter-sqlx crates/batter-sqlx Optional native PostgreSQL connection disposition.
batter-runledger crates/batter-runledger Optional native initialization, stop-clock and settlement integration.
batter-runlimit crates/batter-runlimit Optional native atomic quota-before-work execution and protected authenticated HTTP assembly.
batter-test-support crates/batter-test-support Generic test utilities; independent of the foundation and adapters.
batter-example-postgres-lifecycle examples/postgres-lifecycle Native SQLx composition; an executable, not a library API.
batter-example-reference-service examples/reference-service Atomic authenticated delivery command, provider-effect reconciliation, explicit direct-peer/request correlation, pinned compatibility probes, validated constructors, and an explicit live test target.

PostgreSQL provisioning stays in the external postgres-test-harness repository; it is not a workspace member. The optional batter-sqlx/test-support feature is selected by reference tests; the default adapter graph excludes the harness. The optional batter-runledger adapter owns native initialization and settlement. The reference uses Runledger's transactional producer API and registers one application-owned provider-effect handler. Its selected loopback-test protocol uses a stable key, canonical payload matching, lookup reconciliation and an explicit 24-hour retention boundary; this is not an exactly-once or arbitrary provider guarantee. batter-runlimit preserves native quota decisions and consumption certainty under an operation budget; optional HTTP assembly owns auth/quota/body ordering. Its memory, postgres, and axum features are independent and off by default. It does not own PostgreSQL initialization or maintenance. Run its finite example with cargo run -p batter --features runlimit-memory,runlimit-axum --example quota_service. Ownership boundaries are in integrations; delivery tasks live in the Beads backlog. The compatibility manifest records the reference package's compiled graph and executed live probes. It is not a complete durable service.

Non-negotiable limits

  • A timeout or cancellation drops a future. It does not roll back an external effect or prove a write failed. Nothing here supplies exactly-once effects.
  • The supervisor owns registered critical tasks and admitted finite work. Task Err(E) initiates drain; put expected business rejections in the success value. Dropping a receipt does not stop work or release its permit.
  • Task abortion is not preemption. Joining a server wrapper does not prove detached children stopped. After a panic, requested abort, or unjoined direct task, dependent finalizers are skipped and the report is unsuccessful.
  • Cleanup is explicitly awaited. It is not asynchronous Drop, general cancellation shielding, or a promise to survive SIGKILL. The owned driver continues shutdown when a waiter is cancelled, provided the runtime remains alive.
  • The Axum boundary ends when a response is constructed. Streaming bodies and WebSockets require a separate lifetime design.

These are API contracts and limitations, not footnotes. Read guarantees before putting side effects behind a boundary.

Documentation

To use batter: usage, operations, architecture, guarantees, and security. Crate READMEs in the table above own adapter-level detail.

To work in this repository: AGENTS.md for reading order, verification, and change rules; status and testing for coverage; Beads for delivery tasks. The Effect v4 brief and reconciliation record design rationale. Primary references record upstream checks.

bash scripts/verify.sh
RUSTUP_TOOLCHAIN=1.94.0 bash scripts/verify.sh

Checks preserve Cargo.lock. Use bash scripts/verify.sh --bootstrap only when formatting sources and generating a missing lockfile is intended. Repair compiler, lint, and test failures without weakening the documented contracts.

License

MIT; see LICENSE. Registry publication remains a separate decision.

About

Operational foundation for Rust/Tokio backends: task supervision, graceful shutdown, deadlines, cancellation, explicit retries, and an optional Axum adapter.

Topics

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages