Redis cache
The Redis and RedisSentinel kinds store the values in Redis, so that every instance of a service
sees the same data. Use Redis for a single server or a managed service, and RedisSentinel when Redis Sentinel
provides the failover. This page extends the caching guide.
What it solves
Both classes (RedisCache and RedisSentinelCache) wrap the
Microsoft.Extensions.Caching.StackExchangeRedis distributed cache. Arc4u adds the named configuration and the
serialization of the values. The connection to Redis is opened on the first operation, not when the cache is initialized.
Packages involved
| Package | Use it for |
|---|---|
Arc4u.Caching.Redis |
RedisCache (kind Redis), RedisSentinelCache (kind RedisSentinel) and AddRedisCacheKinds(). |
Arc4u.Caching |
ICacheContext and AddCacheContext. |
Arc4u.Serializer.JSon |
The serializer (any IObjectSerialization works). |
Install
dotnet add package Arc4u.Caching.Redis --prerelease
dotnet add package Arc4u.Serializer.JSon --prerelease
You need a reachable Redis server, or Sentinel nodes, at run time.
Configuration
Redis
{
"Caching": {
"Default": "Shared",
"Caches": [
{
"Name": "Shared",
"Kind": "Redis",
"IsAutoStart": true,
"Settings": {
"ConnectionString": "localhost:6379",
"InstanceName": "MyApp-"
}
}
]
}
}
The settings bind to RedisCacheOption:
| Key | Type | Default | Description |
|---|---|---|---|
Caching:Caches:n:Settings:ConnectionString |
string |
none (required) | A StackExchange.Redis configuration string. |
Caching:Caches:n:Settings:InstanceName |
string |
Default |
Prefix added to every key. Use a distinct value per application when they share a server. |
Caching:Caches:n:Settings:SerializerName |
string |
none | Key of the IObjectSerialization to use. When empty or not registered, the unkeyed one is used. |
AddCacheContext throws an ArgumentNullException for ConnectionString at startup when it is missing.
Redis Sentinel
{
"Caching": {
"Default": "HighAvailability",
"Caches": [
{
"Name": "HighAvailability",
"Kind": "RedisSentinel",
"IsAutoStart": true,
"Settings": {
"InstanceName": "MyApp-",
"MasterName": "mymaster",
"SentinelEndpoints": [ "sentinel-0:26379", "sentinel-1:26379", "sentinel-2:26379" ],
"RedisPassword": "<password>",
"DefaultDatabase": 1
}
}
]
}
}
The settings bind to RedisSentinelCacheOption:
| Key | Type | Default | Description |
|---|---|---|---|
Caching:Caches:n:Settings:InstanceName |
string |
empty (required) | Prefix added to every key. |
Caching:Caches:n:Settings:MasterName |
string |
mymaster |
Name of the monitored master, as declared in the Sentinel configuration. |
Caching:Caches:n:Settings:SentinelEndpoints |
string[] |
empty (at least one required) | Sentinel nodes, as host:port. |
Caching:Caches:n:Settings:RedisPassword |
string |
none | Password used to connect to Redis. |
Caching:Caches:n:Settings:DefaultDatabase |
int? |
0 |
Redis database number. |
Caching:Caches:n:Settings:SerializerName |
string |
none | Key of the IObjectSerialization to use. |
AddCacheContext throws an ArgumentException when InstanceName, MasterName or SentinelEndpoints is empty.
The Sentinel cache does not connect at initialization: it lets StackExchange.Redis discover the master
from MasterName and the endpoints, and connects on the first operation.
Caution
Do not commit the password. Read it from user secrets, an environment variable
(Caching__Caches__0__Settings__RedisPassword) or a secret store.
Code
// Program.cs
using Arc4u.Caching;
using Arc4u.Caching.Redis;
using Arc4u.Dependency;
using Arc4u.Serializer;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddILogger();
builder.Services.AddCacheContext(builder.Configuration);
builder.Services.AddSingleton<IObjectSerialization, JsonSerialization>();
// Registers RedisCache (kind Redis) and RedisSentinelCache (kind RedisSentinel).
builder.Services.AddRedisCacheKinds();
var app = builder.Build();
app.Run();
Common scenarios
Share a cache between two services
Point both services to the same server and use the same InstanceName and the same serializer. Values written by one are
read by the other, so both must be able to deserialize the same type. Use a different InstanceName to isolate two applications
that share a Redis server.
Combine a memory cache and a Redis cache
Declare both and pick by name: keep hot, per-instance data in a Memory cache and data shared across instances in
Redis. See Use several caches.
Extensibility points
AddRedisCacheKinds() registers the classes under the keys Redis and RedisSentinel with TryAddKeyedTransient. Register
another ICache under one of these keys before calling it to replace it. To tune StackExchange.Redis beyond the options
above, register your own ICache (for example one that derives from BaseDistributeCache<T>).
Troubleshooting
ArgumentNullException or ArgumentException at startup
A required setting is missing: ConnectionString for Redis; InstanceName, SentinelEndpoints for RedisSentinel. Check the
index of the cache in Caching:Caches.
A cache with no Settings section is not validated at startup, because nothing is registered for it. A Redis cache then
fails on its first operation with DataCacheException: Value cannot be null. (Parameter 'configuration'); a RedisSentinel
cache throws InvalidOperationException: At least one Sentinel endpoint must be configured. when the ICacheContext is resolved.
Operations fail or time out
The initialization does not contact Redis, so a wrong host appears on the first operation. Get and Put wrap the error in
DataCacheException, with the StackExchange.Redis exception (for example RedisConnectionException) as InnerException;
TryGetValue and Remove return false instead of throwing.
See also
- Caching
- Serialization
- Arc4u.Caching.Redis in the API reference