tsoracle-server 0.1.2

Embeddable gRPC server for the timestamp oracle.
Documentation

Crates.io DeepWiki guide CI Coverage Status License

A distributed timestamp oracle for Rust โ€” highly available and fault-tolerant, issuing strictly monotonic integer timestamps over gRPC, Raft-replicated via openraft with pluggable consensus.

Features

  • ๐Ÿ”ข Strictly monotonic โ€” 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.
  • ๐Ÿ›ก๏ธ Crash-safe โ€” window state is fsync'd before any timestamp in that window is handed out, so a restart never rewinds.
  • ๐Ÿ”Œ Pluggable consensus, openraft included โ€” tsoracle-driver-openraft ships a production-ready replicated driver; implement one trait (ConsensusDriver) to back tsoracle with raft-rs, etcd, or your own replicated log instead.
  • ๐Ÿ“ฆ 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 single-process and multi-process raft topologies.
  • ๐Ÿงฉ 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:

cargo install tsoracle
tsoracle serve

The server listens on 127.0.0.1:50551 and persists state under ./tsoracle-data/.

Then call it from 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

Use as a library

Embed the server in your own binary instead of running the CLI:

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. Want to mount tsoracle inside an existing tonic server? See Server::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, TiDB, 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.

Documentation

  • DeepWiki โ€” prose documentation covering the window allocator, the ConsensusDriver contract, and operational topics (fsync cost, leader handoff, deployment topologies).
  • docs.rs/tsoracle-server โ€” generated API reference.

Examples

  • examples/embedded-server โ€” embed tsoracle-server with the file driver in your own binary, with graceful shutdown.
  • examples/failover-demo โ€” pedagogy: watch the failover fence keep timestamps strictly monotonic across simulated leadership changes, in-process, no openraft.
  • examples/openraft-standalone โ€” HA: three-node multi-process cluster on a dedicated openraft, wired through tsoracle-driver-openraft with a tonic peer transport and follower-redirect via LeaderHint.
  • 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/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-<name>.

Contributing

Issues and pull requests are welcome. See 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.

License

Licensed under Apache-2.0.