RepletoryLib.Caching.Hybrid 1.0.0

dotnet add package RepletoryLib.Caching.Hybrid --version 1.0.0
                    
NuGet\Install-Package RepletoryLib.Caching.Hybrid -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RepletoryLib.Caching.Hybrid" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RepletoryLib.Caching.Hybrid" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="RepletoryLib.Caching.Hybrid" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RepletoryLib.Caching.Hybrid --version 1.0.0
                    
#r "nuget: RepletoryLib.Caching.Hybrid, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RepletoryLib.Caching.Hybrid@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RepletoryLib.Caching.Hybrid&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=RepletoryLib.Caching.Hybrid&version=1.0.0
                    
Install as a Cake Tool

RepletoryLib.Caching.Hybrid

L1/L2 hybrid cache combining in-memory speed with Redis distributed consistency.

Part of the RepletoryLib ecosystem -- standalone, reusable .NET 10 libraries with zero business logic.

NuGet .NET 10 License: MIT


Overview

RepletoryLib.Caching.Hybrid implements ICacheService using a two-tier caching strategy:

  • L1 (In-Memory) -- Ultra-fast, zero-latency local cache for hot data
  • L2 (Redis) -- Distributed cache shared across all application instances

On a cache read, L1 is checked first. On a miss, L2 is checked and the result is promoted to L1. On a write or invalidation, both layers are updated and other instances are notified via Redis pub/sub to evict their L1 entries.

This gives you the speed of in-memory caching with the consistency of distributed caching.

Key Features

  • Two-tier caching -- L1 (IMemoryCache) + L2 (Redis) with automatic promotion
  • L1 invalidation via pub/sub -- Redis pub/sub notifies all instances when cache entries change
  • Configurable TTLs -- Independent expiry for L1 and L2 layers
  • Transparent -- Drop-in replacement for any ICacheService implementation

Installation

dotnet add package RepletoryLib.Caching.Hybrid

Or add to your .csproj:

<PackageReference Include="RepletoryLib.Caching.Hybrid" Version="1.0.0" />

Note: RepletoryLib packages are published to a local BaGet feed. See the main repository README for feed configuration.

Dependencies

Package Type
RepletoryLib.Caching.InMemory RepletoryLib
RepletoryLib.Caching.Redis RepletoryLib

Prerequisites

  • Redis 7+ running and accessible (for L2 and pub/sub)
docker-compose up -d redis

Quick Start

using RepletoryLib.Caching.Hybrid;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRepletoryHybridCache(builder.Configuration);
{
  "RepletoryRedis": {
    "ConnectionString": "localhost:6379",
    "InstanceName": "myapp:",
    "DefaultExpiryMinutes": 60
  },
  "RepletoryHybridCache": {
    "L1ExpiryMinutes": 5,
    "L2ExpiryMinutes": 60
  }
}

Configuration

HybridCacheOptions

Property Type Default Description
L1ExpiryMinutes int 5 In-memory cache TTL (short-lived, local)
L2ExpiryMinutes int 60 Redis cache TTL (long-lived, distributed)

Section name: "RepletoryHybridCache"

L1 expiry should always be shorter than L2. This ensures stale local data is naturally evicted even if a pub/sub message is missed.


Usage Examples

How It Works

GET "user:123"
  ├─ L1 (InMemory) HIT → return immediately (sub-microsecond)
  └─ L1 MISS
       ├─ L2 (Redis) HIT → promote to L1, return
       └─ L2 MISS
            └─ Factory executes → store in L2, store in L1, return

SET "user:123"
  ├─ Store in L1 (local)
  ├─ Store in L2 (Redis)
  └─ Publish invalidation via Redis pub/sub → other instances evict L1

REMOVE "user:123"
  ├─ Remove from L1 (local)
  ├─ Remove from L2 (Redis)
  └─ Publish invalidation → other instances evict L1

Using the Hybrid Cache

using RepletoryLib.Caching.Abstractions.Interfaces;

public class ProductService
{
    private readonly ICacheService _cache;

    public ProductService(ICacheService cache) => _cache = cache;

    public async Task<Product?> GetProductAsync(Guid id)
    {
        // First call: misses L1 and L2, loads from DB, caches in both
        // Second call (same instance): hits L1, returns in <1ms
        // Second call (different instance): hits L2, promotes to L1
        return await _cache.GetOrSetAsync($"product:{id}", async () =>
        {
            return await _repository.GetByIdAsync(id);
        });
    }

    public async Task UpdateProductAsync(Product product)
    {
        await _repository.UpdateAsync(product);

        // Removes from L1, L2, and notifies other instances
        await _cache.RemoveAsync($"product:{product.Id}");
    }
}

When to Use Hybrid vs Redis-Only

Scenario Recommendation
Frequently read, rarely updated Hybrid (L1 absorbs most reads)
Frequently updated data Redis-only (L1 invalidation overhead not worth it)
Single instance InMemory or Hybrid (both fast, Hybrid adds Redis durability)
Multiple instances, read-heavy Hybrid (best performance)
Multiple instances, write-heavy Redis-only

Integration with Other RepletoryLib Packages

Package Relationship
RepletoryLib.Caching.Abstractions Implements ICacheService
RepletoryLib.Caching.InMemory Provides the L1 layer
RepletoryLib.Caching.Redis Provides the L2 layer and pub/sub
RepletoryLib.Auth.Jwt Token blacklist benefits from hybrid speed

Troubleshooting

Issue Solution
L1 cache returns stale data Check Redis connectivity -- pub/sub invalidation requires an active Redis connection
Performance not better than Redis Ensure L1 TTL is long enough for your access patterns. Very short L1 TTL negates the benefit.
Memory growing on L1 Reduce L1ExpiryMinutes. L1 entries are evicted by both TTL and memory pressure.

License

This project is licensed under the MIT License.

Copyright (c) 2024-2026 Repletory.


For complete documentation, infrastructure setup, and configuration reference, see the RepletoryLib main repository.

Product Compatible and additional computed target framework versions.
.NET 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 76 3/2/2026