Clients
Ruvio has first-party clients for six languages. Every one covers all 287 commands in the compatibility matrix with a typed method, plus the options only Ruvio has (SET ... IFEQ, DELEX, FILLGET, LIMIT, Bloom, JSON.FIND and the rest).
A test in each client reads the matrix and fails when a command has no method. Each client has its own page in the Clients menu.
All numbers on these pages come from short runs on a shared 4-vCPU virtual machine, client and server on the same host, over loopback. They show relative cost and allocation, not release-grade throughput.
The six clients
| Client | Model | Cluster | Registry today | Tests (live server) |
|---|---|---|---|---|
| Rust | Blocking, std only, no dependencies | Yes | crates.io ruvio-client latest | unit + coverage + live suites |
| C# | Async, one multiplexed connection | Yes | NuGet Ruvio.Client latest | 198 client tests; 6 integration packages |
| Go | context.Context on every call, one multiplexed connection, standard library only | Yes | Not yet (needs a module tag) | 74 tests, race detector run |
| Java | Blocking facade and CompletableFuture, one multiplexed connection | Yes | Not yet (Maven Central) | 91 tests |
| Python | Sync and asyncio, optional hiredis parser | Yes | Not yet (PyPI) | 217 tests |
| Node.js | Promises, TypeScript types, ESM, no dependencies | Yes | Not yet (npm) | 63 tests |
What they share
The same behaviors, in the idiom of each language:
- One seed address. The client asks
CLUSTER SLOTS, opens one connection per shard and routes by slot. A standalone server answers "cluster mode is disabled" and the client then works as a plain client. MGET,MSET,DEL,UNLINK,EXISTSandTOUCHacross slots are split per slot, sent in parallel, and the replies come back in your order. Other cross-slot calls fail before anything is sent.MOVEDrepairs the slot table and the command is retried once. A command is never replayed after a transport failure.- Pipelines,
MULTI/EXECwithWATCH, Pub/Sub on its own connection, blocking commands that do not stall the shared connection, and a genericexecutefor anything else. - Binary-safe values, server errors as typed errors, and nil replies as null,
None,Optionalor a second return value.
Not shared: the Rust client is blocking only, and the Rust and C# clients have no TLS today. No client handles ASK redirects or replica reads. Each page has the full list.
Built for speed and low memory
Users reach Ruvio through a client, so the clients follow the same rule as the server: no work that is not needed. All of them use these ideas, first proved in the C# client:
- One shared connection. Concurrent callers share a socket and a first-in first-out queue of pending replies. There is no connection pool to size.
- Write coalescing. Frames that are queued while a write is in flight leave in one write, up to 64 KiB. There is no timer and no batching delay; a lone call is sent at once.
- Pre-encoded commands. Command names are stored as finished RESP fragments (
$3\r\nGET\r\n). Integers are written straight into the output buffer. - In-place parsing. Replies are parsed from a reusable read buffer. An integer or
+OKallocates nothing; a bulk allocates only the value you get back.
The same helper layer everywhere
Every client adds small tools on top of the raw commands, so the Ruvio-specific commands are easy to use correctly:
| Helper | Built on | What it gives you |
|---|---|---|
| Distributed lock | SET NX PX, SET IFEQ, DELEX IFEQ | Acquire, renew, release. Release never deletes a lock someone else took after yours expired. Scoped forms release for you. |
| Lease and semaphore | LEASE, SEMAPHORE, RELEASE | A fence token, or a limited number of holders, released when the scope ends. |
| Rate limit | LIMIT | Allowed or not, and how much is left, in one round trip. |
| Get or create | FILLGET, FILLSET | Cache-aside where only one caller runs the factory; the others wait and read the result. Optional stale-while-revalidate. |
| Idempotency | IDEM | Run an action once per key; repeated calls get the stored result. |
| Scan iterators | SCAN, HSCAN, SSCAN, ZSCAN | Lazy loops over the whole keyspace or one collection, across all shards. |
| Typed JSON | JSON.* | Read and write your own types with the language's standard JSON library. |
| Recent list, seen before | LPUSHCAP, BF.MADD, BF.MEXISTS | A list that keeps the last N items, and a "have I seen this" check. |
Cluster
Start a three-shard server with shards = 3 and port_mode = "per-shard". Shard i listens on the base port plus i. Give any client one address and it finds the rest. Each page has a cluster example that was run against such a server. Database 0 only; there is no failover, ASK or live resharding in the server, so none of the clients handle them.
Speed, in one table
Concurrent GET/SET on one shared connection, 64 to 128 callers, standalone server, same VM for client and server. Taken from each client's own benchmark; the figures vary about 2x between runs on this machine.
| Client | Concurrent GET (ops/s) | Compared with |
|---|---|---|
| Go (64 goroutines) | about 260k to 300k | — |
| Node.js (128 in flight) | about 600k to 880k | ioredis 5: about 105k (same run) |
| Python asyncio (64 coroutines) | about 186k to 239k | redis-py 8.1: about 8k (same run) |
| Java (64 threads) | about 140k to 210k | — |
| C# (16 callers) | about 54k to 93k | — |
| Rust (blocking, one thread) | about 17k to 60k | — |
Do not rank the languages from this table: the host was shared with the server, the callers differ, and each row has its own run-to-run noise. A serial call is about 30 to 60 microseconds in every client, and that time is mostly the network round trip and the server, not the client.
The comparisons with ioredis and redis-py ran in the same session on the same server; they show the cost of one connection per request against a shared, coalesced one, not a general ranking of libraries.
Status and gaps
- The repository holds all six. Only the Rust crate and the NuGet packages are on a registry, and those versions are older than the repository. Registry releases for the rest are not set up yet.
- Cluster routing was tested on a three-shard server on one machine, not on a real Redis Cluster and not under failure.
- Some commands were checked only up to the server's reply (ACL file commands without an ACL file, cluster commands on a standalone server). Each page says which.
- Continuous integration for the new clients is not set up yet.
Which one to use
Use the client for your language. For .NET also look at the integration packages (distributed cache, rate limiting, idempotency, output caching, data protection, distributed lock). For examples of the commands themselves, see Commands and Examples.