Skip to content

haxxornulled/VapeCache

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

385 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

VapeCache logo

VapeCache

VapeCache is a Redis-protocol-first caching runtime for ASP.NET Core and .NET services. It is designed for predictable behavior under load, Redis trouble, and high-throughput API traffic.

  • Website: https://vapecache.net

  • Source: https://github.com/haxxornulled/VapeCache

  • Redis/KeyDB-compatible transport tuned for cache workloads

  • Circuit-breaker and in-memory fallback for outage tolerance

  • Stampede controls for hot keys

  • OpenTelemetry metrics + traces

  • ASP.NET Core and Aspire integrations

What The Hybrid Runtime Actually Does

When you register the native runtime with AddVapecacheCaching(), VapeCache is not just acting like a thin Redis wrapper. The hybrid runtime is a production cache execution model with Redis as the primary backend and node-local memory as the failover path.

Native hybrid behavior includes:

  • typed cache-aside APIs through IVapeCache
  • named cache scopes with logical clear boundaries
  • Redis-primary reads and writes with in-memory fallback routing during outages
  • circuit-breaker state and manual failover controls for drills and incident handling
  • stampede protection on hot keys
  • write mirroring and read warming so fallback memory stays useful when Redis is healthy
  • tag and zone version invalidation
  • ASP.NET Core output-cache storage integration
  • OpenTelemetry metrics and tracing for the runtime path

If you want the detailed contract, see docs/HYBRID_CACHING_API_SURFACE.md.

FusionCache Positioning

VapeCache overlaps with FusionCache in important places, but the products are not trying to be the exact same thing.

  • FusionCache is focused on application-facing cache orchestration.
  • VapeCache is focused on a Redis-first runtime with cache APIs, transport control, failover behavior, and framework integrations.
  • If you want FusionCache-style L2 interoperability, VapeCache ships an IDistributedCache / IBufferDistributedCache bridge for that migration path.
  • If you want the full VapeCache model, use the native runtime APIs instead of stopping at the distributed-cache bridge.

The practical message is: VapeCache is not "just another FusionCache". It is a Redis-first runtime choice for teams that care about the whole runtime path (transport, failover, observability, and framework integration), not only the call-site cache abstraction.

See docs/FUSIONCACHE_POSITIONING.md.

No StackExchange.Redis Runtime Dependency

The production VapeCache runtime packages in this repo do not depend on StackExchange.Redis. VapeCache.Runtime ships its own Redis transport/runtime implementation and composes with Microsoft.Extensions.*, Polly, and VapeCache packages.

StackExchange.Redis does appear in benchmark and test surfaces in this repository for interoperability validation. That distinction matters: comparison and validation tooling may depend on it, the runtime does not.

Performance Transparency

Performance data and methodology are tracked in-repo with reproducible benchmark artifacts and disclosure rules.

OSS scope in this repository: production-ready runtime packages for core caching, invalidation, ASP.NET Core integration, and Aspire integration. For OSS/Enterprise boundaries, see docs/OSS_VS_ENTERPRISE.md.

Dependency Ownership

Keep Redis versioning boring:

  • The Redis version line used by the Aspire host is owned by Aspire.Hosting.Redis.
  • The Aspire package version is owned in Directory.Build.props via VapeCacheAspireVersion.
  • Manual Docker examples and test scripts should follow the same Redis major/minor line that Aspire defaults to.
  • Use exact patch pinning only as a deliberate temporary freeze, not as the normal repo default.

Maturity and Evidence

Current project status: Production-Capable.

QuickStart

  1. Install packages
dotnet add package VapeCache.Runtime
dotnet add package VapeCache.Extensions.Aspire

If you need ASP.NET Core output-cache middleware integration:

dotnet add package VapeCache.Extensions.AspNetCore

If you want a DI composition facade for clean architecture wiring:

dotnet add package VapeCache.Extensions.DependencyInjection

If you want an explicit KeyDB package boundary and default KeyDbConnection section binding:

dotnet add package VapeCache.Extensions.KeyDB

If you need an IDistributedCache / IBufferDistributedCache bridge for interoperability or migration:

dotnet add package VapeCache.Extensions.DistributedCache

If you want centralized Serilog + OTEL logging wiring with rolling file sink support and optional JSON formatting:

dotnet add package VapeCache.Extensions.Logging

If you need Redis pub/sub support:

dotnet add package VapeCache.Extensions.PubSub

If you need Redis 8.6 stream idempotent producer support:

dotnet add package VapeCache.Extensions.Streams

If you need HASH-backed RediSearch projections for operational lookup/search workloads:

dotnet add package VapeCache.Features.Search

If you need EF Core second-level cache interceptor contracts and invalidation bridge wiring:

dotnet add package VapeCache.Extensions.EntityFrameworkCore

If you need EF Core cache OpenTelemetry signals (Aspire/OTEL ready):

dotnet add package VapeCache.Extensions.EntityFrameworkCore.OpenTelemetry
  1. Run Redis (or KeyDB)
docker run --name vapecache-redis -p 6379:6379 -d redis:8.6

Manual Docker examples intentionally track the same Redis 8.6 line that the Aspire host gets from Aspire.Hosting.Redis. If we move supported Redis forward, update the Aspire package first and keep the manual examples on that same line.

KeyDB local alternative:

docker run --name vapecache-keydb -p 6379:6379 -d eqalpha/keydb:latest

If you do not have Redis and want a local/lightweight runtime, skip Redis and use AddVapeCacheInMemory(...) instead.

  1. Configure appsettings.json
{
  "RedisConnection": {
    "Host": "localhost",
    "Port": 6379,
    "Database": 0
  }
}
  1. Register VapeCache in Program.cs
using VapeCache.Abstractions.Caching;
using VapeCache.Abstractions.Connections;
using VapeCache.Extensions.Logging;
using VapeCache.Extensions.PubSub;
using VapeCache.Extensions.Streams;
using VapeCache.Infrastructure.Caching;
using VapeCache.Infrastructure.Connections;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOptions<RedisConnectionOptions>()
    .Bind(builder.Configuration.GetSection("RedisConnection"));

builder.Services.AddVapecacheRedisConnections();
builder.Services.AddVapecacheCaching();
builder.Services.AddVapeCachePubSub(); // optional: only when pub/sub is needed
builder.Services.AddVapeCacheStreams(); // optional: only when stream idempotent producer support is needed

builder.Services.AddOptions<CacheStampedeOptions>()
    .UseCacheStampedeProfile(CacheStampedeProfile.Balanced)
    .Bind(builder.Configuration.GetSection("CacheStampede"));

Memory-only alternative for local dev or lightweight single-node hosts:

using VapeCache.Abstractions.Caching;
using VapeCache.Extensions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddVapeCacheInMemory(builder.Configuration)
    .WithCacheStampedeProfile(CacheStampedeProfile.Balanced);
  1. Add one endpoint
var app = builder.Build();

app.MapGet("/products/{id:int}", async (int id, IVapeCache cache, CancellationToken ct) =>
{
    var key = CacheKey<string>.From($"products:{id}");
    var value = await cache.GetOrCreateAsync(
        key,
        _ => new ValueTask<string>($"product-{id}"),
        new CacheEntryOptions(TimeSpan.FromMinutes(5)),
        ct);

    return Results.Ok(value);
});

app.Run();

Named cache scopes are also available:

var catalogCache = app.Services.GetRequiredService<IVapeCache>().NamedCache("catalog");
await catalogCache.ClearAsync();
  1. Go deeper: docs/QUICKSTART.md

ASP.NET Core Policy Ergonomics

VapeCache now supports native ASP.NET Core output-cache ergonomics for both minimal APIs and MVC while keeping the runtime engine untouched.

builder.Services.AddVapeCacheOutputCaching();
builder.Services.AddVapeCacheAspNetPolicies(policies =>
{
    policies.AddPolicy("products", policy => policy
        .Ttl(TimeSpan.FromMinutes(5))
        .VaryByQuery()
        .Tags("products"));
});

app.MapGet("/products/{id:int}", (int id) => Results.Ok(new { id }))
   .CacheWithVapeCache("products");

MVC/controller attributes are also supported:

[VapeCachePolicy("products", TtlSeconds = 300, VaryByQuery = true, CacheTags = new[] { "products" })]
public IActionResult GetProduct(int id) => Ok(new { id });

See:

IDistributedCache Bridge

Already on IDistributedCache or using FusionCache with a distributed L2? VapeCache ships a bridge package for that migration path.

using VapeCache.Extensions.DistributedCache;

builder.Services.AddVapeCache(builder.Configuration)
    .UseDistributedCacheAdapter(options =>
    {
        options.KeyPrefix = "fusion:l2:";
    });

This is intentionally a compatibility layer, not the preferred headline integration. Native VapeCache remains the recommended path when you want the full runtime surface. Recommended framing: keep your current cache abstraction, route the distributed-cache layer through VapeCache, and migrate to native APIs later if you want the fuller runtime model. See docs/DISTRIBUTED_CACHE_BRIDGE.md for the interop positioning and FusionCache guidance.

Microsoft HybridCache

VapeCache can also back Microsoft.Extensions.Caching.Hybrid.HybridCache.

using VapeCache.Extensions.DependencyInjection;

builder.Services.AddVapeCache(builder.Configuration)
    .AddMicrosoftHybridCache(options =>
    {
        options.KeyPrefix = "ms-hc:";
    });

This gives you the Microsoft HybridCache API over the native VapeCache runtime, including tag invalidation and logical clear-all via RemoveByTagAsync("*"). See docs/MICROSOFT_HYBRIDCACHE.md.

Named Caches And Clear

IVapeCache supports named cache scopes and logical clear operations.

var root = app.Services.GetRequiredService<IVapeCache>();
var products = root.NamedCache("products");

await products.SetAsync(CacheKey<string>.From("42"), "espresso");
await products.ClearAsync();

Named caches:

  • prefix keys for that scope
  • attach a reserved scope tag
  • support logical clear via tag invalidation instead of backend scans

Redis Search Projections

For workloads like grocery receipt verification, the recommended plan is to search denormalized HASH projections, not your full source aggregates.

VapeCache.Features.Search gives you:

  • typed TEXT, TAG, and NUMERIC RediSearch schemas
  • generic HASH projection storage
  • query-builder helpers for exact-match, text, and numeric range filters
  • search-result cache key/tag conventions that fit VapeCache.Features.Invalidation

That lets the front-door receipt check invalidate instantly without flattening the rest of the runtime behind a generic search abstraction. See docs/REDIS_SEARCH.md.

Production Packages (OSS)

Package NuGet GitHub Packages Purpose Docs
VapeCache.Runtime VapeCache.Runtime vapecache.runtime Core runtime, Redis transport, fallback behavior, telemetry API Reference
VapeCache.Core VapeCache.Core vapecache.core Shared primitives package (transitive dependency, usually not installed directly) Package Matrix
VapeCache.Abstractions VapeCache.Abstractions vapecache.abstractions Public contracts and option/value types API Reference
VapeCache.Features.Invalidation VapeCache.Features.Invalidation vapecache.features.invalidation Optional key/tag/zone invalidation policies Cache Invalidation
VapeCache.Features.Search VapeCache.Features.Search vapecache.features.search Typed HASH-backed RediSearch projections, query helpers, and invalidation conventions for operational search Redis Search
VapeCache.Extensions.DependencyInjection VapeCache.Extensions.DependencyInjection vapecache.extensions.dependencyinjection One-call IServiceCollection wiring facade for runtime + config binding Quickstart
VapeCache.Extensions.KeyDB VapeCache.Extensions.KeyDB vapecache.extensions.keydb Explicit KeyDB registration facade with default KeyDbConnection binding Package README
VapeCache.Extensions.DistributedCache VapeCache.Extensions.DistributedCache vapecache.extensions.distributedcache IDistributedCache / IBufferDistributedCache bridge for interoperability and migration Package README
VapeCache.Extensions.Logging VapeCache.Extensions.Logging vapecache.extensions.logging Optional Serilog + OTEL logging wiring with file/Seq/console sinks and pluggable JSON formatting Logging + Telemetry
VapeCache.Extensions.PubSub VapeCache.Extensions.PubSub vapecache.extensions.pubsub Optional Redis pub/sub package (publish/subscribe, bounded queues, reconnect/resubscribe) API Reference
VapeCache.Extensions.Streams VapeCache.Extensions.Streams vapecache.extensions.streams Optional Redis 8.6 streams package for idempotent producers (XADD IDMP/IDMPAUTO, XCFGSET) Package README
VapeCache.Extensions.EntityFrameworkCore VapeCache.Extensions.EntityFrameworkCore vapecache.extensions.entityframeworkcore EF Core second-level cache interceptor contracts, deterministic query-key builder, and SaveChanges invalidation bridge wiring EF Core Second-Level Cache
VapeCache.Extensions.EntityFrameworkCore.OpenTelemetry VapeCache.Extensions.EntityFrameworkCore.OpenTelemetry vapecache.extensions.entityframeworkcore.opentelemetry OpenTelemetry metrics/activity package for EF Core cache interceptor events and profiler correlation EF Core package README
VapeCache.Extensions.AspNetCore VapeCache.Extensions.AspNetCore vapecache.extensions.aspnetcore ASP.NET Core output-cache integration ASP.NET Core Pipeline
VapeCache.Extensions.Aspire VapeCache.Extensions.Aspire vapecache.extensions.aspire Aspire wiring, health checks, endpoint helpers Aspire Integration

Full package install matrix: docs/NUGET_PACKAGES.md GitHub profile/About/topic/social branding: docs/GITHUB_BRANDING.md Public website and doc home: https://vapecache.net

Out Of OSS Scope

The following are not shipped from this OSS repository:

  • adaptive autoscaling of multiplexed lanes
  • enterprise licensing and control-plane features
  • durable spill persistence package
  • reconciliation package for post-outage write replay

Multiplexing itself is OSS; adaptive autoscaling is Enterprise.

Documentation

Build And Test

dotnet build VapeCache.slnx -c Release
dotnet test VapeCache.Tests/VapeCache.Tests.csproj -c Release

License

VapeCache OSS is licensed under the MIT License.

That means you can use, modify, redistribute, and commercialize the code with very few conditions. The main obligations are to keep the copyright notice and license text with substantial portions of the software.

Important boundary:

  • the code is MIT-licensed
  • the VapeCache name, logos, package identity, and brand assets are not granted to you under MIT

See LICENSE for the license text, docs/LICENSE_FAQ.md for quick answers, and docs/TRADEMARK_POLICY.md for brand and naming rules.

About

Redis-first caching runtime for .NET 10 with hybrid failover, stampede protection, output caching, and deep OpenTelemetry observability.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors