Skip to main content

Redis Session Store

Vali-Blob.Redis provides RedisResumableSessionStore, a production-ready session store backed by Redis via StackExchange.Redis. Sessions are serialized to JSON and stored as Redis string keys with a configurable sliding TTL.

Use the Redis store when your application runs on multiple instances or containers — it ensures all pods share the same session state, so a chunk can be uploaded to a different instance than the one that started the session.


Installation

dotnet add package Vali-Blob.Redis

Registration

using Vali-Blob.Core;
using Vali-Blob.AWS;
using Vali-Blob.Redis;

builder.Services
.AddVali-Blob(o => o.DefaultProvider = "aws")
.AddProvider<AWSS3Provider>("aws", o =>
{
o.BucketName = builder.Configuration["AWS:BucketName"]!;
o.Region = builder.Configuration["AWS:Region"]!;
o.AccessKey = builder.Configuration["AWS:AccessKey"]!;
o.SecretKey = builder.Configuration["AWS:SecretKey"]!;
})
.AddRedisSessionStore(opts =>
{
opts.ConnectionString = builder.Configuration["Redis:ConnectionString"]!;
opts.KeyPrefix = "valiblob:session:";
opts.SlidingExpiration = TimeSpan.FromHours(24);
});

Configuration Options

OptionTypeDefaultDescription
ConnectionStringstring"localhost:6379"StackExchange.Redis connection string
KeyPrefixstring"valiblob:session:"Prefix prepended to every Redis key
SlidingExpirationTimeSpan24 hoursTTL reset on every chunk upload
DatabaseIndexint0Redis logical database index
JsonOptionsJsonSerializerOptions?nullCustom JSON serialization options

Connection String Formats

Standalone Redis

localhost:6379
my-redis.example.com:6379,password=secret,ssl=true,abortConnect=false

Redis Sentinel (High Availability)

sentinel1.example.com:26379,sentinel2.example.com:26379,serviceName=mymaster,password=secret

Redis Cluster

cluster-node1.example.com:6379,cluster-node2.example.com:6379,password=secret,abortConnect=false

Azure Cache for Redis

my-cache.redis.cache.windows.net:6380,password=<access-key>,ssl=true,abortConnect=false

AWS ElastiCache

my-elasticache.abc123.ng.0001.use1.cache.amazonaws.com:6379,abortConnect=false

TTL Behavior

Sessions are stored as Redis keys with a sliding TTL:

  • Created (SaveAsync) → TTL set to SlidingExpiration
  • Read or updated (GetAsync, UpdateAsync) → TTL reset to SlidingExpiration
  • Deleted (DeleteAsync) → key removed immediately

Active uploads (where chunks arrive regularly) never expire. Only uploads that go stale — no chunk arrives for the full TTL window — are automatically cleaned up by Redis with no background job required.

Session created:       TTL = 24h
Chunk 1 uploaded: TTL reset to 24h
Chunk 2 uploaded: TTL reset to 24h
...
24h with no activity → key expires → GetAsync returns null → session gone

Tuning TTL for large uploads on slow connections

opts.SlidingExpiration = TimeSpan.FromDays(7);  // allow up to 7 days to complete

Stored Session Format

Sessions are serialized to compact JSON, typically under 512 bytes per session:

{
"uploadId": "abc123",
"path": "uploads/videos/my-video.mp4",
"totalSize": 104857600,
"uploadedBytes": 52428800,
"contentType": "video/mp4",
"createdAt": "2026-03-18T10:00:00Z",
"updatedAt": "2026-03-18T10:05:00Z",
"status": "InProgress"
}

Inspect sessions from the Redis CLI:

# List all active sessions
redis-cli KEYS "valiblob:session:*"

# Inspect a specific session
redis-cli GET "valiblob:session:abc123"

# Check remaining TTL
redis-cli TTL "valiblob:session:abc123"

Reusing an Existing IConnectionMultiplexer

If your application already registers IConnectionMultiplexer (e.g., for distributed caching or pub/sub), Vali-Blob will reuse it automatically:

// Register shared connection globally
builder.Services.AddSingleton<IConnectionMultiplexer>(
ConnectionMultiplexer.Connect(builder.Configuration["Redis:ConnectionString"]!));

// Vali-Blob resolves and reuses the registered multiplexer
builder.Services
.AddVali-Blob(...)
.AddRedisSessionStore(opts =>
{
opts.KeyPrefix = "valiblob:session:";
opts.SlidingExpiration = TimeSpan.FromHours(24);
// ConnectionString not needed — multiplexer resolved from DI
});

Multi-Instance Kubernetes Deployment

All pods share the same Redis instance. A client can start an upload on Pod A and send chunks to Pod B — all pods will find the same session in Redis:

# kubernetes/deployment.yaml
env:
- name: Redis__ConnectionString
valueFrom:
secretKeyRef:
name: app-secrets
key: redis-connection-string
// Program.cs — identical on all pods
builder.Services
.AddVali-Blob(...)
.AddRedisSessionStore(opts =>
{
opts.ConnectionString = builder.Configuration["Redis:ConnectionString"]!;
opts.KeyPrefix = "myapp:valiblob:session:";
opts.SlidingExpiration = TimeSpan.FromHours(24);
});
Unique KeyPrefix per application

When multiple applications share the same Redis instance, always set a distinct KeyPrefix (include the app name) to avoid session key collisions between applications.


Health Check Integration

builder.Services
.AddHealthChecks()
.AddRedis(builder.Configuration["Redis:ConnectionString"]!, name: "redis-session-store")
.AddVali-Blob("storage-aws", factory => factory.Create("aws")); // storage provider health

app.MapHealthChecks("/health");

Diagnosing Connection Issues

Confirm the correct store is registered

// In development, verify the store type
var store = app.Services.GetRequiredService<IResumableSessionStore>();
Console.WriteLine(store.GetType().Name);
// Should print: RedisResumableSessionStore
// If it prints: InMemoryResumableSessionStore — AddRedisSessionStore was not called

Add connection timeouts for remote Redis

my-redis.example.com:6379,connectTimeout=5000,syncTimeout=5000,abortConnect=false

When to Use Redis vs EF Core

ScenarioRedisEF Core
Multiple app instances / podsYesYes
Already running RedisYes
Already running a SQL database, no RedisYes
Automatic TTL cleanup (no background job)YesNo (needs background job)
Query sessions by path or userNoYes
Embedded SQLite (no external service)Yes