https://github.com/prisma-risk/tsoracle
Distributed timestamp & sequence oracle for Rust โ strictly monotonic timestamps and gapless, dense ID sequences, raft-replicated over gRPC.
https://github.com/prisma-risk/tsoracle
distributed gapless gapless-sequence grpc monotonic mvcc openraft rust sequence timestamp timestamp-oracle tso
Last synced: 16 days ago
JSON representation
Distributed timestamp & sequence oracle for Rust โ strictly monotonic timestamps and gapless, dense ID sequences, raft-replicated over gRPC.
- Host: GitHub
- URL: https://github.com/prisma-risk/tsoracle
- Owner: prisma-risk
- License: apache-2.0
- Created: 2026-05-19T18:40:22.000Z (29 days ago)
- Default Branch: main
- Last Pushed: 2026-05-30T13:01:45.000Z (18 days ago)
- Last Synced: 2026-05-30T15:14:58.134Z (18 days ago)
- Topics: distributed, gapless, gapless-sequence, grpc, monotonic, mvcc, openraft, rust, sequence, timestamp, timestamp-oracle, tso
- Language: Rust
- Homepage: https://tsoracle.rs
- Size: 3.81 MB
- Stars: 44
- Watchers: 1
- Forks: 2
- Open Issues: 8
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Codeowners: .github/CODEOWNERS
- Security: SECURITY.md
- Governance: GOVERNANCE.md
- Roadmap: ROADMAP.md
Awesome Lists containing this project
README
[](https://crates.io/crates/tsoracle)
[](https://deepwiki.com/prisma-risk/tsoracle)


[](https://github.com/prisma-risk/tsoracle/actions/workflows/ci.yml)
[](https://github.com/prisma-risk/tsoracle/actions/workflows/stress-nightly.yml)
[](https://coveralls.io/github/prisma-risk/tsoracle?branch=main)
[](https://scorecard.dev/viewer/?uri=github.com/prisma-risk/tsoracle)
[](https://www.bestpractices.dev/projects/12991)
A distributed timestamp **and sequence** oracle for Rust โ highly available and fault-tolerant, issuing strictly monotonic integer timestamps and gapless, dense ID sequences over gRPC, replicated via openraft or OmniPaxos (or your own log) with pluggable consensus.
## Features
- ๐ข **Strictly monotonic timestamps** โ every issued timestamp is strictly greater than every previously issued one; no duplicates and no regression, ever. The packed integer space is not dense (logical resets when `physical_ms` advances, so some integer values are unused), but the issued sequence is total-ordered and unique. Call `get_ts` when you need *order*.
- ๐ **Gapless sequences** โ `get_seq(key, count)` hands out dense, contiguous ID blocks `[start, start + count)` per named key โ nothing skipped, never reused across crashes or failover โ for surrogate keys, invoice numbers, ledger lines, or partition offsets. The tradeoff is non-idempotency: an ambiguous failure surfaces as `SeqUncertain` for the caller to reconcile rather than being silently retried. Call `get_seq` when you need *no holes*. Implemented on the file and openraft drivers today (OmniPaxos on the roadmap).
- ๐ก๏ธ **Crash-safe** โ window state is fsync'd before any timestamp in that window is handed out, so a restart never rewinds.
- ๐ **Pluggable consensus, openraft + OmniPaxos included** โ `tsoracle-driver-openraft` and `tsoracle-driver-paxos` ship production-ready replicated drivers; implement one trait (`ConsensusDriver`) to back tsoracle with raft-rs, etcd, or your own replicated log instead. See [`docs/consensus-integration.md`](docs/consensus-integration.md#choosing-a-driver) for picking between drivers.
- ๐ฆ **gRPC client included** โ `tsoracle-client` handles leader discovery, request coalescing, and reconnection for you.
- ๐ **Operational metrics** โ enable the `metrics` feature on `tsoracle-server` to emit allocator, leader, and request metrics through the `metrics` facade.
- ๐งช **Hardened** โ coverage-guided fuzzing on the postcard decoders, failpoint-driven crash tests, and a stress harness covering in-process and multi-process topologies across the openraft and OmniPaxos backends.
- ๐งฉ **Embeddable** โ host the server inside your own binary with a few lines of Rust, or run the standalone CLI.
## Quickstart
Install the standalone binary and start the server:
```bash
cargo install tsoracle
tsoracle
```
Releases are signed with SLSA build provenance โ see [Verifying release signatures](docs/release-signatures.md).
Bare `tsoracle` is shorthand for `tsoracle serve file`. The server listens on `127.0.0.1:50551` and persists state under `./tsoracle-data/`.
Then call it from Rust:
```rust
use tsoracle_client::Client;
let client = Client::connect(vec!["http://127.0.0.1:50551".into()]).await?;
let ts = client.get_ts().await?; // a strictly increasing Timestamp
let batch = client.get_ts_batch(64).await?; // amortize RPC cost across many IDs
let block = client.get_seq("orders", 64).await?; // 64 gapless IDs: [start, start + 64)
```
## Use as a library
Embed the server in your own binary instead of running the CLI:
```rust
use tsoracle_server::Server;
use tsoracle_driver_file::FileDriver;
let driver = FileDriver::open_or_init("./tsoracle-data")?;
let server = Server::builder()
.consensus_driver(driver)
.build()?;
server
.serve_with_shutdown("127.0.0.1:50551".parse()?, async {
let _ = tokio::signal::ctrl_c().await;
})
.await?;
```
A complete, runnable version lives in [`examples/embedded-server`](examples/embedded-server). Want to mount tsoracle inside an existing tonic server? See [`Server::into_router`](https://docs.rs/tsoracle-server/latest/tsoracle_server/struct.Server.html#method.into_router).
## What's a TSO?
A *timestamp oracle* is a service that hands out strictly increasing integer IDs which order events across a distributed system. You reach for one when:
- You're building a database with snapshot isolation or MVCC (Spanner, CockroachDB, FoundationDB all use a TSO internally).
- You need to merge change-data from many shards into one globally ordered stream.
- You want audit logs with a real "happens-before" relation across machines.
- Per-host clocks aren't monotonic or accurate enough, and database sequences don't scale to your workload.
tsoracle is a small, embeddable Rust implementation. The consensus layer is left as a trait, so you can run it single-node behind one fsync (the default), or wire it into a replicated log of your choice.
Beyond ordering, tsoracle also issues **gapless sequences**. Where a timestamp only has to be *ordered* (and may skip values), a sequence has to be *contiguous* โ `โฆ, 41, 42, 43, โฆ` with nothing missing. Call `get_seq(key, count)` for surrogate keys, invoice or order numbers, ledger line numbers, or partition offsets, with one durable, gapless counter per named key. The cost is non-idempotency, since a gapless advance can't be un-spent โ see [Gapless sequences with GetSeq](https://tsoracle.rs/posts/gapless-sequences-with-getseq/) for the full story and [`docs/client-api-and-usage.md`](docs/client-api-and-usage.md) for the API.
## Documentation
- [DeepWiki](https://deepwiki.com/prisma-risk/tsoracle) โ prose documentation covering the window allocator, the `ConsensusDriver` contract, and operational topics (fsync cost, leader handoff, deployment topologies).
- [docs.rs/tsoracle-server](https://docs.rs/tsoracle-server) โ generated API reference.
## Project documents
- [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) โ Contributor Covenant v2.1.
- [`CONTRIBUTING.md`](CONTRIBUTING.md) โ how to contribute, including the DCO sign-off requirement.
- [`GOVERNANCE.md`](GOVERNANCE.md) โ roles, decision-making, and continuity-of-access plan.
- [`ROADMAP.md`](ROADMAP.md) โ near / mid / long-term direction.
- [`SECURITY.md`](SECURITY.md) โ vulnerability reporting and response commitments.
- [`docs/assurance-case.md`](docs/assurance-case.md) โ safety and security claims with supporting evidence.
- [`docs/release-signatures.md`](docs/release-signatures.md) โ verifying release provenance and signed tags.
## Maintainers
- **Sebastian Thiebaud** ([@sebastianthiebaud](https://github.com/sebastianthiebaud)) โ lead maintainer.
- **Charles Merill** ([@crmerrill](https://github.com/crmerrill)) โ co-maintainer.
- **Idriss Maoui** ([@idmao](https://github.com/idmao)) โ co-maintainer.
See [`GOVERNANCE.md`](GOVERNANCE.md) for roles, authorities, and the continuity-of-access plan.
## Examples
- [examples/embedded-server](examples/embedded-server) โ embed `tsoracle-server` with the file driver in your own binary, with graceful shutdown.
- [examples/failover-demo](examples/failover-demo) โ pedagogy: watch the failover fence keep timestamps strictly monotonic across simulated leadership changes, in-process, no openraft.
- [examples/openraft-standalone](examples/openraft-standalone) โ HA: three-node multi-process cluster on a dedicated openraft, wired through [`tsoracle-driver-openraft`](crates/tsoracle-driver-openraft/) with a tonic peer transport and follower-redirect via `LeaderHint`.
- [examples/openraft-piggyback](examples/openraft-piggyback) โ HA: in-process three-node demo of the envelope pattern, where your service's existing openraft carries both your `AppData` and the tsoracle `HighWaterCommand` on a single log, with one snapshot covering both halves.
- [examples/paxos-standalone](examples/paxos-standalone) โ HA: three-node multi-process cluster on a dedicated OmniPaxos, wired through [`tsoracle-driver-paxos`](crates/tsoracle-driver-paxos/) with a tonic peer transport and follower-redirect via `LeaderHint`.
- [examples/paxos-piggyback](examples/paxos-piggyback) โ HA: in-process three-node demo of the envelope pattern on OmniPaxos, where your service's existing paxos log carries both your `AppData` and the tsoracle `HighWaterCommand`, with one snapshot covering both halves.
- [examples/paxos-embedded](examples/paxos-embedded) โ HA: single-process 3-node OmniPaxos cluster (OmniPaxos rejects single-node configs, so even "embedded" runs all three nodes in-memory). The closest paxos equivalent to `embedded-server`.
- [examples/metrics-prometheus](examples/metrics-prometheus) โ embed `tsoracle-server` with `metrics-exporter-prometheus` installed before the server starts, exposing `/metrics` on a separate port for Prometheus to scrape; swap recorders with a one-line change.
Each example is its own crate. Build with `cargo run -p example-`.
## Contributing
Issues and pull requests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for local setup, the checks CI will run on your PR, commit message conventions, and the release process.
### Contributors
Made with [contrib.rocks](https://contrib.rocks).
## License
Licensed under [Apache-2.0](LICENSE).