Generate code patterns for StackExchange.Redis.Extensions — Streams, Geo, VectorSet, Hash, Pub/Sub, Sets, Compression
Generate production-ready code patterns using StackExchange.Redis.Extensions.
When the user asks to implement:
public class ProductService(IRedisDatabase redis, IProductRepository repo)
{
public async Task<Product?> GetProductAsync(int id)
{
var key = $"product:{id}";
var cached = await redis.GetAsync<Product>(key);
if (cached is not null)
return cached;
var product = await repo.GetByIdAsync(id);
if (product is not null)
await redis.AddAsync(key, product, TimeSpan.FromMinutes(30));
return product;
}
}
public class OrderProcessor(IRedisDatabase redis)
{
public async Task ProcessAsync(CancellationToken ct)
{
await redis.StreamCreateConsumerGroupAsync("orders", "processors", "0-0", createStream: true);
while (!ct.IsCancellationRequested)
{
var entries = await redis.StreamReadGroupAsync("orders", "processors", "worker-1", ">", count: 10); // ">" = read only new messages
foreach (var entry in entries)
{
try
{
// Process message
await redis.StreamAcknowledgeAsync("orders", "processors", entry.Id.ToString());
}
catch
{
// Message stays in PEL for retry
}
}
if (entries.Length == 0)
await Task.Delay(1000, ct);
}
}
}
public class StoreLocator(IRedisDatabase redis)
{
public async Task<GeoRadiusResult[]> FindNearbyAsync(double lat, double lon, double radiusKm)
{
return await redis.GeoSearchAsync("stores", lon, lat,
new GeoSearchCircle(radiusKm, GeoUnit.Kilometers),
count: 20, order: Order.Ascending);
}
public async Task AddStoreAsync(string id, double lat, double lon)
{
await redis.GeoAddAsync("stores", lon, lat, id);
}
}
public class DocumentSearch(IRedisDatabase redis)
{
public async Task IndexAsync(string docId, float[] embedding, string title)
{
await redis.VectorSetAddAsync("docs",
VectorSetAddRequest.Member(docId, embedding,
attributes: $"""{{ "title": "{title}" }}"""));
}
public async Task<List<(string Id, double Score)>> SearchAsync(float[] queryVector, int topK = 5)
{
using var results = await redis.VectorSetSimilaritySearchAsync("docs",
VectorSetSimilaritySearchRequest.ByVector(queryVector) with { Count = topK });
var items = new List<(string, double)>();
if (results is not null)
foreach (var r in results.Span)
items.Add((r.Member!, r.Score));
return items;
}
}
public class SessionStore(IRedisDatabase redis)
{
public async Task SetSessionDataAsync(string userId, string token, object profile)
{
var hashKey = $"user:{userId}";
// Permanent profile data
await redis.HashSetAsync(hashKey, "profile", profile);
// Session token expires in 30 minutes
await redis.HashSetWithExpiryAsync(hashKey, "token", token, TimeSpan.FromMinutes(30));
}
}
public class EventBus(IRedisDatabase redis)
{
public async Task PublishAsync<T>(string channel, T message)
{
await redis.PublishAsync(new RedisChannel(channel, RedisChannel.PatternMode.Literal), message);
}
public async Task SubscribeAsync<T>(string channel, Func<T?, Task> handler)
{
await redis.SubscribeAsync<T>(new RedisChannel(channel, RedisChannel.PatternMode.Literal), handler);
}
}
public async Task CacheBulkAsync(IRedisDatabase redis, Dictionary<string, Product> products)
{
var items = products.Select(p => Tuple.Create($"product:{p.Key}", p.Value)).ToArray();
await redis.AddAllAsync(items, TimeSpan.FromHours(1));
}
redis.Database directly