Skip to content

fkucukkara/hybridcache_playground

Repository files navigation

Hybrid Cache Playground

A .NET 10 educational demo project showcasing Hybrid Cache with Redis, demonstrating how to leverage both local in-memory cache and distributed cache (Redis) for optimal performance.

🎯 Overview

This project demonstrates a practical implementation of Microsoft.Extensions.Caching.Hybrid, which combines:

  • Local Cache: Fast in-memory cache for frequently accessed data
  • Distributed Cache (Redis): Shared cache across multiple instances

The demo uses PostgreSQL as the database and showcases different cache expiration strategies for various scenarios.

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   API Layer     β”‚
β”‚  (Minimal APIs) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  CachedProductService    β”‚
β”‚  (Hybrid Cache Layer)    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
    β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”
    β”‚        β”‚
β”Œβ”€β”€β”€β–Όβ”€β”€β”€β” β”Œβ”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Local β”‚ β”‚  Redis      β”‚
β”‚ Cache β”‚ β”‚ (Distributed)β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ ProductService  β”‚
β”‚ (Database Layer)β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  PostgreSQL     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

✨ Features

  • Hybrid Cache Implementation: Demonstrates local + distributed caching
  • Different Expiration Times:
    • Short-lived cache (10s local, 1min distributed) for both product list and individual product queries
    • Demonstrates cache invalidation strategies for maintaining data consistency
  • Cache Invalidation: Automatic cache invalidation on create/update/delete operations
  • Aspire Integration: Uses .NET Aspire for orchestration and observability
  • PostgreSQL Database: Real database with EF Core
  • RESTful API: Clean minimal API endpoints

πŸš€ Getting Started

Prerequisites

  • .NET 10 SDK
  • Docker Desktop (for PostgreSQL and Redis via Aspire)

Running the Application

  1. Clone the repository

    git clone <repository-url>
    cd HybridCachePlayground
  2. Run the Aspire AppHost

    dotnet run --project HybridCachePlayground.AppHost

    This will:

    • Start PostgreSQL database
    • Start Redis cache
    • Start the API application (3 replicas)
    • Open Aspire Dashboard in your browser
  3. Access the API

    • API: https://localhost:3000
    • Aspire Dashboard: Automatically opens in browser
    • OpenAPI/Swagger: Available in development mode

πŸ“š API Endpoints

Get All Products

GET /api/products

Returns all products. Uses hybrid cache with:

  • Local cache: 10 seconds
  • Distributed cache: 1 minute

Get Product by ID

GET /api/products/{id}

Returns a specific product. Uses hybrid cache with:

  • Local cache: 10 seconds
  • Distributed cache: 1 minute

Create Product

POST /api/products
Content-Type: application/json

{
  "name": "New Product",
  "description": "Product description",
  "price": 99.99,
  "stock": 50
}

Creates a new product and invalidates the products list cache.

Update Product

PUT /api/products/{id}
Content-Type: application/json

{
  "name": "Updated Product",
  "description": "Updated description",
  "price": 109.99,
  "stock": 45
}

Updates a product and invalidates related caches.

Delete Product

DELETE /api/products/{id}

Deletes a product and invalidates related caches.

πŸ” Cache Strategy Explained

Cache Configuration

Both endpoints use the same cache expiration strategy:

  • Local Cache: 10 seconds
  • Distributed Cache: 1 minute

This configuration provides:

  • Fast local access: Frequently requested data is served from in-memory cache for ultra-fast response times
  • Shared cache across instances: Distributed cache (Redis) ensures cache hits even when requests hit different API instances
  • Automatic cache invalidation: When products are created, updated, or deleted, related caches are automatically invalidated to maintain data consistency

Cache Invalidation

When products are created, updated, or deleted:

  • The specific product cache is invalidated
  • The products list cache is invalidated
  • This ensures data consistency across all instances

πŸ§ͺ Testing the Cache

Test Cache Behavior

  1. First Request (Cache Miss):

    curl https://localhost:3000/api/products/1
    • Check logs: You'll see "Fetching product 1 from database"
    • Response time: ~100ms (simulated DB latency)
  2. Second Request (Cache Hit):

    curl https://localhost:3000/api/products/1
    • Check logs: No database query
    • Response time: <1ms (from local cache)
  3. Request from Different Instance:

    • Since we run 3 replicas, hit the same endpoint from a different instance
    • First request from new instance: Cache miss (local), but may hit Redis
    • Subsequent requests: Cache hit from local cache

Observing Cache Behavior

Use the Aspire Dashboard to:

  • Monitor cache hit/miss rates
  • View distributed tracing
  • Check Redis connection status
  • Monitor database queries

πŸ› οΈ Technology Stack

  • .NET 10 with C# 14
  • Microsoft.Extensions.Caching.Hybrid - Hybrid caching
  • StackExchange.Redis - Redis client
  • Entity Framework Core 10 - ORM
  • Npgsql.EntityFrameworkCore.PostgreSQL - PostgreSQL provider
  • .NET Aspire - Cloud-native orchestration
  • Minimal APIs - Lightweight API endpoints

πŸ“– Key Concepts Demonstrated

  1. Hybrid Cache: Combining local and distributed cache for optimal performance
  2. Cache Expiration Strategies: Different TTLs based on data characteristics
  3. Cache Invalidation: Ensuring data consistency
  4. Multi-Instance Support: Distributed cache enables cache sharing across instances
  5. Performance Optimization: Reducing database load through intelligent caching

πŸŽ“ Learning Points

  • When to use Hybrid Cache: Best for scenarios where you need both fast local access and shared cache across instances
  • Expiration Strategy: Balance between freshness and performance - shorter local cache ensures quick updates while distributed cache reduces database load
  • Cache Invalidation: Critical for maintaining data consistency - the demo shows how to invalidate both specific item caches and list caches
  • Cache Tags: Using tags (e.g., ["products"]) enables bulk invalidation if needed in the future
  • Monitoring: Use Aspire Dashboard to observe cache behavior, hit/miss rates, and distributed tracing

πŸ“ Project Structure

HybridCachePlayground/
β”œβ”€β”€ HybridCachePlayground/
β”‚   β”œβ”€β”€ Data/
β”‚   β”‚   └── AppDbContext.cs          # EF Core DbContext
β”‚   β”œβ”€β”€ DTOs/
β”‚   β”‚   β”œβ”€β”€ CreateProductRequest.cs
β”‚   β”‚   └── UpdateProductRequest.cs
β”‚   β”œβ”€β”€ Models/
β”‚   β”‚   └── Product.cs               # Product entity
β”‚   β”œβ”€β”€ Services/
β”‚   β”‚   β”œβ”€β”€ ProductService.cs        # Database service
β”‚   β”‚   └── CachedProductService.cs  # Hybrid cache wrapper
β”‚   └── Program.cs                   # Application entry point
β”œβ”€β”€ HybridCachePlayground.AppHost/
β”‚   └── AppHost.cs                   # Aspire orchestration
└── README.md

🀝 Contributing

This is an educational demo project. Feel free to fork and experiment with different cache strategies and scenarios!

πŸ“„ License

This project is provided as-is for educational purposes.


Built with ❀️ using .NET 10 and Aspire

About

A .NET 10 educational demo project showcasing Hybrid Cache with Redis, demonstrating how to leverage both local in-memory cache and distributed cache (Redis) for optimal performance.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages