An open API service indexing awesome lists of open source software.

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.

Awesome Lists containing this project

README

          




tsoracle



[![Crates.io](https://img.shields.io/crates/v/tsoracle.svg)](https://crates.io/crates/tsoracle)
[![DeepWiki](https://img.shields.io/badge/DeepWiki-tsoracle-blue.svg)](https://deepwiki.com/prisma-risk/tsoracle)
![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)
![Crates.io](https://img.shields.io/crates/d/tsoracle-core.svg)


[![CI](https://github.com/prisma-risk/tsoracle/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/prisma-risk/tsoracle/actions/workflows/ci.yml)
[![stress](https://github.com/prisma-risk/tsoracle/actions/workflows/stress-nightly.yml/badge.svg?branch=main)](https://github.com/prisma-risk/tsoracle/actions/workflows/stress-nightly.yml)
[![Coverage Status](https://coveralls.io/repos/github/prisma-risk/tsoracle/badge.svg?branch=main)](https://coveralls.io/github/prisma-risk/tsoracle?branch=main)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/prisma-risk/tsoracle/badge)](https://scorecard.dev/viewer/?uri=github.com/prisma-risk/tsoracle)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/12991/badge)](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).