[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-81804":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":13,"stars30d":17,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":20,"hasPages":22,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":31,"readmeContent":32,"aiSummary":33,"trendingCount":16,"starSnapshotCount":16,"syncStatus":13,"lastSyncTime":34,"discoverSource":35},81804,"tsoracle","prisma-risk\u002Ftsoracle","prisma-risk","Distributed timestamp & sequence oracle for Rust — strictly monotonic timestamps and gapless, dense ID sequences over gRPC, replicated with pluggable consensus.","https:\u002F\u002Ftsoracle.rs",null,"Rust",55,2,1,25,0,20,44.43,"Apache License 2.0",false,"main",true,[24,25,26,27,28,29,30],"grpc","mvcc","openraft","rust","timestamp","timestamp-oracle","tso","2026-06-12 04:01:35","\u003Cdiv align=\"center\">\n    \u003Cpicture>\n        \u003Csource media=\"(prefers-color-scheme: dark)\" srcset=\"site\u002Fstatic\u002Ftsoracle-dark.svg\">\n        \u003Cimg alt=\"tsoracle\" src=\"site\u002Fstatic\u002Ftsoracle-light.svg\" width=\"360\">\n    \u003C\u002Fpicture>\n    \u003Cbr \u002F>\u003Cbr \u002F>\n\n[![Crates.io](https:\u002F\u002Fimg.shields.io\u002Fcrates\u002Fv\u002Ftsoracle.svg)](https:\u002F\u002Fcrates.io\u002Fcrates\u002Ftsoracle)\n[![DeepWiki](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FDeepWiki-tsoracle-blue.svg)](https:\u002F\u002Fdeepwiki.com\u002Fprisma-risk\u002Ftsoracle)\n![License](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-Apache--2.0-blue.svg)\n![Crates.io](https:\u002F\u002Fimg.shields.io\u002Fcrates\u002Fd\u002Ftsoracle-core.svg)\n\u003Cbr\u002F>\n[![CI](https:\u002F\u002Fgithub.com\u002Fprisma-risk\u002Ftsoracle\u002Factions\u002Fworkflows\u002Fci.yml\u002Fbadge.svg?branch=main)](https:\u002F\u002Fgithub.com\u002Fprisma-risk\u002Ftsoracle\u002Factions\u002Fworkflows\u002Fci.yml)\n[![stress](https:\u002F\u002Fgithub.com\u002Fprisma-risk\u002Ftsoracle\u002Factions\u002Fworkflows\u002Fstress-nightly.yml\u002Fbadge.svg?branch=main)](https:\u002F\u002Fgithub.com\u002Fprisma-risk\u002Ftsoracle\u002Factions\u002Fworkflows\u002Fstress-nightly.yml)\n[![Coverage Status](https:\u002F\u002Fcoveralls.io\u002Frepos\u002Fgithub\u002Fprisma-risk\u002Ftsoracle\u002Fbadge.svg?branch=main)](https:\u002F\u002Fcoveralls.io\u002Fgithub\u002Fprisma-risk\u002Ftsoracle?branch=main)\n[![OpenSSF Scorecard](https:\u002F\u002Fapi.scorecard.dev\u002Fprojects\u002Fgithub.com\u002Fprisma-risk\u002Ftsoracle\u002Fbadge)](https:\u002F\u002Fscorecard.dev\u002Fviewer\u002F?uri=github.com\u002Fprisma-risk\u002Ftsoracle)\n[![OpenSSF Best Practices](https:\u002F\u002Fwww.bestpractices.dev\u002Fprojects\u002F12991\u002Fbadge)](https:\u002F\u002Fwww.bestpractices.dev\u002Fprojects\u002F12991)\n\n\u003C\u002Fdiv>\n\nA 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.\n\n## Features\n\n- 🔢 **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*.\n- 🆔 **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).\n- 🛡️ **Crash-safe** — window state is fsync'd before any timestamp in that window is handed out, so a restart never rewinds.\n- 🔌 **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\u002Fconsensus-integration.md`](docs\u002Fconsensus-integration.md#choosing-a-driver) for picking between drivers.\n- 📦 **gRPC client included** — `tsoracle-client` handles leader discovery, request coalescing, and reconnection for you.\n- 📈 **Operational metrics** — enable the `metrics` feature on `tsoracle-server` to emit allocator, leader, and request metrics through the `metrics` facade.\n- 🧪 **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.\n- 🧩 **Embeddable** — host the server inside your own binary with a few lines of Rust, or run the standalone CLI.\n\n## Quickstart\n\nInstall the standalone binary and start the server:\n\n```bash\ncargo install tsoracle\ntsoracle\n```\n\nReleases are signed with SLSA build provenance — see [Verifying release signatures](docs\u002Frelease-signatures.md).\n\nBare `tsoracle` is shorthand for `tsoracle serve file`. The server listens on `127.0.0.1:50551` and persists state under `.\u002Ftsoracle-data\u002F`.\n\nThen call it from Rust:\n\n```rust\nuse tsoracle_client::Client;\n\nlet client = Client::connect(vec![\"http:\u002F\u002F127.0.0.1:50551\".into()]).await?;\n\nlet ts = client.get_ts().await?;             \u002F\u002F a strictly increasing Timestamp\nlet batch = client.get_ts_batch(64).await?;  \u002F\u002F amortize RPC cost across many IDs\n\nlet block = client.get_seq(\"orders\", 64).await?;  \u002F\u002F 64 gapless IDs: [start, start + 64)\n```\n\n## Use as a library\n\nEmbed the server in your own binary instead of running the CLI:\n\n```rust\nuse tsoracle_server::Server;\nuse tsoracle_driver_file::FileDriver;\n\nlet driver = FileDriver::open_or_init(\".\u002Ftsoracle-data\")?;\nlet server = Server::builder()\n    .consensus_driver(driver)\n    .build()?;\n\nserver\n    .serve_with_shutdown(\"127.0.0.1:50551\".parse()?, async {\n        let _ = tokio::signal::ctrl_c().await;\n    })\n    .await?;\n```\n\nA complete, runnable version lives in [`examples\u002Fembedded-server`](examples\u002Fembedded-server). Want to mount tsoracle inside an existing tonic server? See [`Server::into_router`](https:\u002F\u002Fdocs.rs\u002Ftsoracle-server\u002Flatest\u002Ftsoracle_server\u002Fstruct.Server.html#method.into_router).\n\n## What's a TSO?\n\nA *timestamp oracle* is a service that hands out strictly increasing integer IDs which order events across a distributed system. You reach for one when:\n\n- You're building a database with snapshot isolation or MVCC (Spanner, CockroachDB, FoundationDB all use a TSO internally).\n- You need to merge change-data from many shards into one globally ordered stream.\n- You want audit logs with a real \"happens-before\" relation across machines.\n- Per-host clocks aren't monotonic or accurate enough, and database sequences don't scale to your workload.\n\ntsoracle 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.\n\nBeyond 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:\u002F\u002Ftsoracle.rs\u002Fposts\u002Fgapless-sequences-with-getseq\u002F) for the full story and [`docs\u002Fclient-api-and-usage.md`](docs\u002Fclient-api-and-usage.md) for the API.\n\n## Documentation\n\n- [DeepWiki](https:\u002F\u002Fdeepwiki.com\u002Fprisma-risk\u002Ftsoracle) — prose documentation covering the window allocator, the `ConsensusDriver` contract, and operational topics (fsync cost, leader handoff, deployment topologies).\n- [docs.rs\u002Ftsoracle-server](https:\u002F\u002Fdocs.rs\u002Ftsoracle-server) — generated API reference.\n\n## Project documents\n\n- [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) — Contributor Covenant v2.1.\n- [`CONTRIBUTING.md`](CONTRIBUTING.md) — how to contribute, including the DCO sign-off requirement.\n- [`GOVERNANCE.md`](GOVERNANCE.md) — roles, decision-making, and continuity-of-access plan.\n- [`ROADMAP.md`](ROADMAP.md) — near \u002F mid \u002F long-term direction.\n- [`SECURITY.md`](SECURITY.md) — vulnerability reporting and response commitments.\n- [`docs\u002Fassurance-case.md`](docs\u002Fassurance-case.md) — safety and security claims with supporting evidence.\n- [`docs\u002Frelease-signatures.md`](docs\u002Frelease-signatures.md) — verifying release provenance and signed tags.\n\n## Maintainers\n\n- **Sebastian Thiebaud** ([@sebastianthiebaud](https:\u002F\u002Fgithub.com\u002Fsebastianthiebaud)) — lead maintainer.\n- **Charles Merill** ([@crmerrill](https:\u002F\u002Fgithub.com\u002Fcrmerrill)) — co-maintainer.\n- **Idriss Maoui** ([@idmao](https:\u002F\u002Fgithub.com\u002Fidmao)) — co-maintainer.\n\nSee [`GOVERNANCE.md`](GOVERNANCE.md) for roles, authorities, and the continuity-of-access plan.\n\n## Examples\n\n- [examples\u002Fembedded-server](examples\u002Fembedded-server) — embed `tsoracle-server` with the file driver in your own binary, with graceful shutdown.\n- [examples\u002Ffailover-demo](examples\u002Ffailover-demo) — pedagogy: watch the failover fence keep timestamps strictly monotonic across simulated leadership changes, in-process, no openraft.\n- [examples\u002Fopenraft-standalone](examples\u002Fopenraft-standalone) — HA: three-node multi-process cluster on a dedicated openraft, wired through [`tsoracle-driver-openraft`](crates\u002Ftsoracle-driver-openraft\u002F) with a tonic peer transport and follower-redirect via `LeaderHint`.\n- [examples\u002Fopenraft-piggyback](examples\u002Fopenraft-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.\n- [examples\u002Fpaxos-standalone](examples\u002Fpaxos-standalone) — HA: three-node multi-process cluster on a dedicated OmniPaxos, wired through [`tsoracle-driver-paxos`](crates\u002Ftsoracle-driver-paxos\u002F) with a tonic peer transport and follower-redirect via `LeaderHint`.\n- [examples\u002Fpaxos-piggyback](examples\u002Fpaxos-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.\n- [examples\u002Fpaxos-embedded](examples\u002Fpaxos-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`.\n- [examples\u002Fmetrics-prometheus](examples\u002Fmetrics-prometheus) — embed `tsoracle-server` with `metrics-exporter-prometheus` installed before the server starts, exposing `\u002Fmetrics` on a separate port for Prometheus to scrape; swap recorders with a one-line change.\n\nEach example is its own crate. Build with `cargo run -p example-\u003Cname>`.\n\n## Contributing\n\nIssues 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.\n\n### Contributors\n\n\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fprisma-risk\u002Ftsoracle\u002Fgraphs\u002Fcontributors\">\n  \u003Cimg src=\"https:\u002F\u002Fcontrib.rocks\u002Fimage?repo=prisma-risk\u002Ftsoracle\"\u002F>\n\u003C\u002Fa>\n\nMade with [contrib.rocks](https:\u002F\u002Fcontrib.rocks).\n\n## License\n\nLicensed under [Apache-2.0](LICENSE).\n","tsoracle 是一个为 Rust 设计的分布式时间戳和序列生成器，具备高可用性和容错性，通过 gRPC 发布严格单调递增的时间戳及无间隙的密集ID序列。该项目的核心功能包括生成不会重复且永不回退的严格单调递增时间戳，以及提供连续、不跳号的序列号用于替代键、发票编号等场景。此外，它还支持故障恢复后状态的一致性保证，并允许用户根据需求选择不同的共识算法实现（如 openraft 或 OmniPaxos）。适用于需要高度一致性和可靠性的分布式系统中，特别是在金融交易处理、日志记录等对数据顺序有严格要求的应用场合。","2026-06-11 04:06:45","CREATED_QUERY"]