Respire.Caching
0.7.14
Prefix Reserved
See the version list below for details.
dotnet add package Respire.Caching --version 0.7.14
NuGet\Install-Package Respire.Caching -Version 0.7.14
<PackageReference Include="Respire.Caching" Version="0.7.14" />
<PackageVersion Include="Respire.Caching" Version="0.7.14" />
<PackageReference Include="Respire.Caching" />
paket add Respire.Caching --version 0.7.14
#r "nuget: Respire.Caching, 0.7.14"
#:package Respire.Caching@0.7.14
#addin nuget:?package=Respire.Caching&version=0.7.14
#tool nuget:?package=Respire.Caching&version=0.7.14
Respire
A fast, modern Redis client for .NET, with distributed locks, rate limiters, and even server assisted client cache.
Works with Redis, Valkey, KeyDB, and other RESP-compatible servers.
Documentation · Getting started · Benchmarks · Coming from StackExchange.Redis?
dotnet add package Respire
await using var redis = await RespireClient.ConnectAsync("redis://localhost");
await redis.SetAsync("user:1", new User("Ada", 36), expiry: TimeSpan.FromMinutes(5));
User? user = await redis.GetAsync<User>("user:1");
Status: Respire is pre-release, so its API may still change. See the roadmap.
Why Respire?
- Plain .NET types. Get
string?,long,bool, or your ownT?, not protocol wrappers. - Fast by default. Concurrent calls are pipelined automatically. Blocking commands get their own connection, so they never stall other calls.
- Hot reads from memory. Turn on client-side caching and Redis tells Respire when to evict.
- Every command. Typed APIs for each data type, and a generated catalog of every Redis 8.10 and Valkey 9.1 command.
- Ready for production. Cluster, Sentinel, reconnection, OpenTelemetry, and dependency injection are built in.
Batteries included
| You need | With Respire |
|---|---|
| A distributed lock | redis.Locks.AcquireAsync(key, expiry) |
| A shared rate limit | redis.Coordination.RateLimiters.SlidingWindow(...) |
| A cross-process semaphore | redis.Coordination.CreateSemaphore(key, capacity) |
| A work queue | redis.Lists.LeftPopAsync(key, waitFor: timeout) |
| Pub/sub | await foreach over redis.SubscribeAsync(channel) |
| Stream consumer groups | await foreach over redis.Streams.ReadGroupAsync(...) |
| Hot reads without a round trip | ClientSideCache = new() |
IDistributedCache and HybridCache |
services.AddRespireHybridCache(connectionString) |
| Tests without Docker | new RespireFakeServer() |
Distributed locks
Run a job on one instance only. Disposing the attempt releases the lock:
await using var attempt = await redis.Locks.AcquireAsync("locks:nightly-report", TimeSpan.FromSeconds(30));
if (attempt.Acquired)
{
await RunReportAsync();
}
Waiting and keep-alive renewal are one call each. See the locks guide.
Rate limiting
Respire.Coordination returns standard .NET RateLimiter instances, shared by every process
that uses the same key. They also work with the ASP.NET Core rate-limiting middleware.
using System.Threading.RateLimiting;
using Respire.Coordination;
await using var limiter = redis.Coordination.RateLimiters.SlidingWindow(
$"limits:api:{userId}", permitLimit: 100, window: TimeSpan.FromMinutes(1), segments: 6);
using var lease = await limiter.AcquireAsync(1, cancellationToken);
if (!lease.IsAcquired && lease.TryGetMetadata(MetadataName.RetryAfter, out TimeSpan retryAfter))
{
Console.WriteLine($"Slow down. Try again in {retryAfter}.");
}
Semaphores and more
Allow at most four exports at once, across all your servers:
using Respire.Coordination;
var exports = redis.Coordination.CreateSemaphore("permits:exports", capacity: 4);
await using var attempt = await exports.TryAcquireAsync(TimeSpan.FromSeconds(30));
if (attempt.Acquired)
{
await RunReportAsync();
}
The same package has read-write locks, countdown latches, leases, and Redlock. See the coordination guide.
Client-side caching
Set one option. Repeated reads then come from local memory, and Redis sends an invalidation when the key changes:
await using var cachedRedis = await RespireClient.ConnectAsync(new RespireOptions
{
Endpoints = { new RespireEndpoint("localhost") },
ClientSideCache = new(),
});
string? name = await cachedRedis.GetStringAsync("user:42:name"); // Cached after the first read.
A cache hit takes hundreds of nanoseconds instead of a network round trip.
Tests without Docker
Respire.Testing runs your real client code against an in-memory server with a fake clock:
using Respire.Testing;
var clock = new RespireFakeClock();
await using var server = new RespireFakeServer(clock);
await using var client = await RespireClient.ConnectAsync(server.CreateOptions());
await client.SetAsync("session", "abc", expiry: TimeSpan.FromMinutes(20));
clock.Advance(TimeSpan.FromMinutes(21));
string? expired = await client.GetStringAsync("session"); // null
Batches and Cluster
Queue commands, send them in one flush, and read typed results:
using var batch = redis.CreateBatch();
var name = batch.GetString("name");
var visits = batch.Increment("visits");
await batch.ExecuteAsync();
Console.WriteLine($"{name.Result}: {visits.Result}");
For Redis Cluster, add ?cluster=true to the connection string. Respire handles slot routing
and redirects. See transactions
and connections.
ASP.NET Core
builder.Services.AddRespire(builder.Configuration.GetConnectionString("redis")!);
builder.Services.AddRespireHybridCache("redis://localhost", instanceName: "myapp:");
The client connects lazily, so startup never waits for Redis. The cache uses the same layout as
Microsoft.Extensions.Caching.StackExchangeRedis, so existing entries keep working.
Packages
| Package | Adds |
|---|---|
Respire |
The client, locks, pub/sub, streams, batches, Cluster, and Sentinel |
Respire.Coordination |
Rate limiters, semaphores, read-write locks, latches, and Redlock |
Respire.DependencyInjection |
AddRespire and keyed clients |
Respire.Caching, Respire.Caching.Hybrid |
IDistributedCache and HybridCache |
Respire.Json, .Search, .TimeSeries, .Probabilistic |
Typed module APIs such as redis.Json |
Respire.Testing, Respire.Testing.Containers |
An in-memory server, or Redis in a container |
See all packages.
Learn more
- Documentation
- Benchmarks
- NativeAOT and custom serializers
- StackExchange.Redis comparison and migration
License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.Caching.Abstractions (>= 10.0.12)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.12)
- Microsoft.Extensions.Options (>= 10.0.12)
- Respire (>= 0.7.14)
-
net8.0
- Microsoft.Extensions.Caching.Abstractions (>= 10.0.12)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.12)
- Microsoft.Extensions.Options (>= 10.0.12)
- Respire (>= 0.7.14)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Respire.Caching:
| Package | Downloads |
|---|---|
|
Respire.Caching.Hybrid
HybridCache L2 backend integration backed by Respire. |
GitHub repositories
This package is not used by any popular GitHub repositories.