Skill: Cosmos Repository Pattern with Redis Cache
When to Use
Adding a new entity type that needs durable persistence with fast reads.
Pattern
- Model: Add
IdandPartitionKeyproperties to the entity class - Cosmos Repo: Create a concrete class extending
CosmosRepositoryBase<T>. OverridePrepareForCosmosto set Id + PartitionKey - DI Wiring: Register concrete repo as singleton, then register
CachedRepository<T>asIRepository<T>with Redis key functions - Test Fixture: Add
RedisBackedRepository<T>registration inChargebackApiFactory.cs
Template
// 1. Model
public sealed class MyEntity {
public string Id { get; set; } = string.Empty;
public string PartitionKey { get; set; } = "my-entity";
// ... fields
}
// 2. Repo
public sealed class CosmosMyEntityRepository : CosmosRepositoryBase<MyEntity> {
public CosmosMyEntityRepository(ConfigurationContainerProvider p, ILogger<CosmosMyEntityRepository> l)
: base(p, "my-entity", l) { }
protected override void PrepareForCosmos(MyEntity e) {
e.Id = e.SomeId;
e.PartitionKey = "my-entity";
}
}
// 3. Program.cs
builder.Services.AddSingleton<CosmosMyEntityRepository>();
builder.Services.AddSingleton<IRepository<MyEntity>>(sp =>
new CachedRepository<MyEntity>(
sp.GetRequiredService<CosmosMyEntityRepository>(),
sp.GetRequiredService<IConnectionMultiplexer>(),
id => $"my-entity:{id}",
entity => entity.SomeId,
sp.GetRequiredService<ILogger<CachedRepository<MyEntity>>>()));
// 4. Test fixture (ChargebackApiFactory.cs)
RemoveService<IRepository<MyEntity>>(services);
services.AddSingleton<IRepository<MyEntity>>(
new RedisBackedRepository<MyEntity>(Redis, id => $"my-entity:{id}", e => e.SomeId, "my-entity:*"));
Key Constraints
- Cosmos partition key value must match the
PartitionKeyproperty default and the string inPrepareForCosmos - Redis key function in
CachedRepositorymust matchRedisKeys.*patterns GetAllAsyncqueries Cosmos (not Redis scan) for completenessCacheWarmingService.csmust be updated to warm the new entity type on startup