BlitzCache 2.1.0
dotnet add package BlitzCache --version 2.1.0
NuGet\Install-Package BlitzCache -Version 2.1.0
<PackageReference Include="BlitzCache" Version="2.1.0" />
<PackageVersion Include="BlitzCache" Version="2.1.0" />
<PackageReference Include="BlitzCache" />
paket add BlitzCache --version 2.1.0
#r "nuget: BlitzCache, 2.1.0"
#:package BlitzCache@2.1.0
#addin nuget:?package=BlitzCache&version=2.1.0
#tool nuget:?package=BlitzCache&version=2.1.0
โก BlitzCache
๐ Enterprise-grade caching that's ridiculously simple to use
One line of code prevents duplicate execution of expensive operations. BlitzCache is production-ready, ultra-fast (0.0001ms operations), and completely thread-safe. No configuration required.
โจ Why BlitzCache?
The Problem: Multiple concurrent calls = Multiple expensive operations
// Without BlitzCache: Expensive operations run multiple times
Task.Run(() => ExpensiveApiCall()); // Executes
Task.Run(() => ExpensiveApiCall()); // Executes again! ๐ธ
Task.Run(() => ExpensiveApiCall()); // And again! ๐ธ๐ธ
The Solution: One line of code changes everything
// With BlitzCache: One execution, all callers get the result
Task.Run(() => cache.BlitzGet("api-call", ExpensiveApiCall)); // Executes once
Task.Run(() => cache.BlitzGet("api-call", ExpensiveApiCall)); // Waits for result โณ
Task.Run(() => cache.BlitzGet("api-call", ExpensiveApiCall)); // Waits for result โณ
// All concurrent calls receive the SAME result when the first one completes!
๐ก๏ธ The Thundering Herd Protection
// Scenario: 100 users hit your API at the exact same moment
for (int i = 0; i < 100; i++)
{
Task.Run(async () => {
// Without BlitzCache: 100 SQL queries hit your database simultaneously ๐ฅ
// With BlitzCache: Only 1 SQL query executes, 99 others wait and get the result โก
var userData = await cache.BlitzGet($"user_{userId}",
() => database.GetSlowUserData(userId),
300000);
});
}
๐ Automatic Statistics
[12:51:32 INF] ***[Customers-Microservice] BlitzCache Statistics***
Hits: 22
Misses: 24
Hit Ratio: 47.83 %
Entries: 2
Evictions: 20
Active Semaphores: 0
Total Operations: 46
Approx. Memory: 120.75 KB
Top Heaviest:
users_cache - ~96 KB
products_cache - ~20 KB
Top Slowest Queries:
LoadBlitzSafe_UsageFromView_819735987 - Worse: 18266ms | Best: 93ms | Avg: 2014 | Occurrences: 10
LoadBlitzSafe_MarketingView_819735987 - Worse: 8608ms | Best: 198ms | Avg: 4403 | Occurrences: 2
LoadBlitzSafe_BillingView_-2041290683 - Worse: 655ms | Best: 107ms | Avg: 228 | Occurrences: 7
CalculateAllDatesFromMarketing - Worse: 408ms | Best: 34ms | Avg: 201 | Occurrences: 3
Perfect for protecting:
- ๐๏ธ SQL Server - Prevents slow query pile-ups that can crash databases
- ๐ External APIs - Avoids rate limiting and reduces costs
- ๐ File System - Prevents I/O bottlenecks from concurrent reads
- ๐งฎ Heavy Calculations - CPU-intensive operations run once, benefit everyone
๐ Enterprise Features, Simple API
โ
Zero duplicate execution - Guaranteed single execution per cache period
โ
Ultra-fast performance - 0.0001ms per operation with intelligent memory management
โ
Thread-safe by design - Handles any concurrency scenario automatically
โ
Memory leak prevention - Advanced cleanup prevents memory bloat
โ
Production tested - Comprehensive testing ensure reliability
โ
Works with everything - Sync, async, any data type, any .NET app
โ
Automatic logging - Built-in statistics monitoring with one line setup (v2.0.1+)
โ
Global statistics - As of v2.0.2, Statistics available and BlitzCacheLoggingService to log them automatically
โ
Top Slowest Queries - As of v2.0.2, BlitzCache tracks and exposes the top slowest queries, making it easy to identify performance bottlenecks in your application
โ
Approximate Memory Usage - As of v2.1.0, statistics include approximate memory usage for better monitoring
โ
Top Heaviest Entries - As of v2.1.0, easily identify the largest cached items with the top heaviest entries feature
โ
Capacity-Based Size Limit (Optional) - As of v2.1.0, set maxCacheSizeBytes
to enable automatic eviction when the cache exceeds a size budget
๐ Table of Contents
- Why BlitzCache?
- Key Features
- Performance Benefits
- Installation
- Quick Start
- Learning BlitzCache - Examples & Tutorials
- Real-World Examples
- Advanced Usage
- API Reference
- Comparison
- Contributing
- Migration Guide
๐ Real Impact
Scenario | Without BlitzCache | With BlitzCache | Impact |
---|---|---|---|
1000 concurrent API calls | 1000 executions | 1 execution | 99.9% faster |
Database query bursts | Multiple DB hits | Single DB hit | Massive savings |
SQL server under load | Server crashes ๐ฅ | Server protected ๐ก๏ธ | System stability |
Operation speed | Varies | 0.0001ms | Lightning fast |
Detailed benchmarks and analysis โ
๐ฆ Get Started in 30 Seconds
dotnet add package BlitzCache
๐ Requirements: Your project needs .NET Core 3.1+ or .NET 5-8+. No special SDK required for usage.
๐ฅ For Contributors: Development requires .NET 8.0 SDK (see CONTRIBUTING.md)
Basic Usage
var cache = new BlitzCache(maxCacheSizeBytes: 200_000_000); // optional size limit
// Any expensive operation becomes cached instantly
var data = await cache.BlitzGet("key", ExpensiveOperation, timeoutMs);
ASP.NET Core Integration
// Setup (one line in Program.cs)
services.AddBlitzCache(maxCacheSizeBytes: 200_000_000);
// Optional: Add automatic logging of cache statistics (v2.0.2+)
services.AddBlitzCacheLogging(); // Logs cache performance hourly
// Usage anywhere
public WeatherService(IBlitzCache cache) => this.cache = cache;
public Task<Weather> GetWeather(string city) => cache.BlitzGet($"weather_{city}", () => CallWeatherApi(city));
Compatibility: .NET Standard 2.1+ | .NET Core 3.1+ | .NET 5-8+
๐ง Advanced Usage
Capacity-Based Size Limit
BlitzCache can enforce an overall cache size budget using .NET MemoryCacheโs SizeLimit. Enable it by providing maxCacheSizeBytes
:
// Instance-based
var cache = new BlitzCacheInstance(maxCacheSizeBytes: 100 * 1024 * 1024); // 100 MB
// Global
var global = new BlitzCache(maxCacheSizeBytes: 100 * 1024 * 1024);
// DI
services.AddBlitzCache(maxCacheSizeBytes: 100 * 1024 * 1024);
How it works:
- Each entry is assigned an approximate size using a lightweight IValueSizer.
- MemoryCache evicts entries (LRU-like with priority) when inserting would exceed SizeLimit.
- Enforced regardless of whether statistics are enabled.
Notes:
- Sizing is best-effort and optimized for common types (string, byte[], primitive arrays). Other types use a conservative default.
- You can still use expiration times; capacity-based eviction works in addition to them.
Automatic Cache Key Generation
BlitzCache can automatically generate cache keys based on the calling method and file:
// Cache key will be: "GetUserData" + "UserService.cs"
public async Task<UserData> GetUserData()
{
return await _cache.BlitzGet(async () => await FetchUserDataAsync());
}
Dynamic Cache Duration Based on Results
public async Task<ApiResponse> CallExternalApiAsync(string endpoint)
{
return await _cache.BlitzGet($"api_{endpoint}", async (nuances) => {
try
{
var result = await httpClient.GetAsync(endpoint);
if (result.IsSuccessStatusCode)
{
nuances.CacheRetention = 300000; // Success: cache for 5 minutes
return await result.Content.ReadFromJsonAsync<ApiResponse>();
}
else
{
nuances.CacheRetention = 30000; // Error: cache for 30 seconds
return new ApiResponse { Error = "API call failed" };
}
}
catch (Exception)
{
nuances.CacheRetention = 5000; // Exception: cache for 5 seconds
return new ApiResponse { Error = "Network error" };
}
});
}
Manual Cache Management
// Update cache manually
cache.BlitzUpdate("user_123", () => GetFreshUserData(), 120000);
// Remove from cache
cache.Remove("user_123");
// Async update
await cache.BlitzUpdate("weather_data", async () => await GetWeatherAsync(), 300000);
Cache Statistics and Monitoring
BlitzCache provides built-in performance statistics to help you monitor cache effectiveness and optimize your application.
As of v2.1.0+, statistics include approximate memory usage and top heaviest entries when enabled (defaults on):
var stats = cache.Statistics;
Console.WriteLine($"Approx Memory: {FormatBytes(stats.ApproximateMemoryBytes)}");
foreach (var heavy in stats.TopHeaviestEntries)
Console.WriteLine($" {heavy}"); // HeavyEntry prints with human-friendly units
static string FormatBytes(long bytes)
{
if (bytes < 1024) return $"{bytes} bytes";
var kb = bytes / 1024.0;
if (kb < 1024) return $"{kb:0.##} KB";
var mb = kb / 1024.0;
return $"{mb:0.##} MB";
}
Notes:
- Memory accounting is best-effort and uses a lightweight sizer for common types (strings, byte[] and primitive arrays). Custom sizing can be added in future versions.
- Heaviest list size is configurable via AddBlitzCache(..., maxTopHeaviest: 5).
Available Statistics:
HitCount
: Total cache hits since instance creationMissCount
: Total cache misses since instance creationHitRatio
: Hit percentage (0.0 to 1.0)TotalOperations
: Sum of hits and missesCurrentEntryCount
: Current number of cached entriesEvictionCount
: Number of manual removals and expirationsActiveSemaphoreCount
: Current concurrency control structuresTopSlowestQueries
: List of the slowest cache operations (v2.0.2+)TopHeaviestEntries
: List of the heaviest cache entries (v2.1.0+)ApproximateMemoryBytes
: Approximate memory usage in bytes (v2.1.0+)Reset()
: Method to reset all counters to zero
Practical guidance:
- Use BlitzGet/BlitzUpdate APIs; they set AbsoluteExpiration and wire eviction callbacks for you.
- For manual removals via Remove, statistics are updated through the eviction callback automaticallyโno extra work needed.
- In tests, very small delays are used to allow callbacks to run; in production these callbacks execute automatically on the thread pool.
๐ API Reference
Core Methods
BlitzGet<T>(string cacheKey, Func<T> function, long? milliseconds = null)
Executes function and caches result for synchronous operations.
BlitzGet<T>(string cacheKey, Func<Task<T>> function, long? milliseconds = null)
Executes async function and caches result for asynchronous operations.
BlitzGet<T>(Func<T> function, long? milliseconds = null)
Auto-generates cache key based on caller method and file path.
BlitzGet<T>(string cacheKey, Func<Nuances, T> function, long? milliseconds = null)
Allows dynamic cache duration configuration via the Nuances
parameter.
Management Methods
BlitzUpdate<T>(string cacheKey, Func<T> function, long milliseconds)
Manually updates cache entry with new value.
Remove(string cacheKey)
Removes specific entry from cache.
Dispose()
Cleans up resources (implements IDisposable).
Parameters
cacheKey
: Unique identifier for the cached valuefunction
: The function to execute and cachemilliseconds
: Cache duration in milliseconds (optional, uses default if not specified)nuances
: Object for dynamic cache configuration
๐ Comparison with Alternatives
Feature | BlitzCache | MemoryCache | Redis | Custom Solutions |
---|---|---|---|---|
Zero Duplicate Execution | โ | โ | โ | โ ๏ธ Complex |
Thread Safety | โ | โ | โ | โ ๏ธ Manual |
Granular Locking | โ | โ | โ | โ ๏ธ Manual |
Async Support | โ | โ | โ | โ ๏ธ Manual |
Simple API | โ | โ | โ | โ ๏ธ Varies |
No External Dependencies | โ | โ | โ | โ |
Performance Overhead | Very Low | Low | Medium | Varies |
Setup Complexity | None | Low | High | High |
Why Choose BlitzCache?
- Prevents Thundering Herd: Unlike basic caches, BlitzCache prevents multiple concurrent executions
- Zero Configuration: Works out of the box with sensible defaults
- Performance Focused: Designed specifically for high-concurrency scenarios
- Developer Friendly: Simple, intuitive API that "just works"
- ๏ฟฝ Enterprise Grade: Advanced memory leak prevention with comprehensive testing
- โก Ultra-Fast: 0.0001ms per operation with optimal memory management
- ๐ก๏ธ Robust Architecture: Advanced usage-based cleanup system
- ๐ง Production Ready: Intelligent smart lock management
๐ ๏ธ Troubleshooting
Common Issues
Q: Cache doesn't seem to work / function executes multiple times
- Ensure you're using the same cache key for identical operations
- Check that cache duration is appropriate for your use case
- Verify you're not creating multiple BlitzCache instances unnecessarily
Q: Memory usage growing over time
- BlitzCache automatically expires entries based on your specified durations
- Consider shorter cache durations for frequently changing data
- Use
Remove()
method for manual cleanup when needed
Q: Async methods hanging or deadlocking
- Ensure you're using
await
properly with async BlitzGet methods - Avoid mixing sync and async patterns
- Check for circular dependencies in your cached functions
Q: Performance not as expected
- Verify your expensive operations are actually expensive enough to benefit from caching
- Check cache hit ratios - very short cache durations may not provide benefits
- Consider whether granular locking is needed for your use case
Getting Help
- ๐ Detailed Blog Post
- ๐ Report Issues
- ๐ฌ Discussions
- ๐ Performance Details & Test Results
๐ฏ Production-Ready Caching Solution
BlitzCache delivers enterprise-grade performance and reliability:
- โ Zero memory leaks - Advanced usage-based cleanup
- โ 0.0001ms per operation - Ultra-high performance
- โ Every feature is tested - Comprehensive reliability
- โ Advanced architecture - Intelligent memory management
- โ Thread-safe - Concurrent operation guarantees
Perfect for demanding production workloads! ๐
๐ ๏ธ Migration Guide: 1.x โ 2.x
If you are upgrading from BlitzCache 1.x to 2.x, please note the following breaking changes:
- Async BlitzUpdate Signature: The
BlitzUpdate<T>
method for async operations now returns aTask
instead ofvoid
. Update your code toawait
these calls:- Before (v1.x):
void BlitzUpdate<T>(string cacheKey, Func<Task<T>> function, long milliseconds);
- After (v2.x):
Task BlitzUpdate<T>(string cacheKey, Func<Task<T>> function, long milliseconds);
- Before (v1.x):
- API Cleanup: Obsolete and redundant APIs have been removed. Review the new interface for available methods.
- Unified Concurrency Control: All concurrency is now managed with SemaphoreSlim. Remove any code referencing SmartLockDictionary or SmartLock classes.
- Instance-Based Caching: BlitzCache is now instance-based instead of static. Update your code to create and manage BlitzCache instances as needed.
Migration Steps:
- Update your NuGet reference to BlitzCache 2.x.
- Refactor all async
BlitzUpdate
usages to return and await aTask
. - Update all projects using BlitzCache to be compatible with the new interface.
- Review and update any code referencing removed or changed APIs.
- Run your test suite to ensure all caching and concurrency scenarios work as expected.
For full details, see the Changelog.
๐ค Contributing
We welcome contributions! Here's how you can help:
Ways to Contribute
- ๐ Report bugs or issues
- ๐ก Suggest new features or improvements
- ๐ Improve documentation
- ๐ง Submit pull requests
- โญ Star the repository
- ๐ข Share with other developers
Development Setup
git clone https://github.com/chanido/blitzcache.git
cd blitzcache
dotnet restore
dotnet build
dotnet test
Pull Request Guidelines
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Write tests for your changes
- Ensure all tests pass
- Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
Code of Conduct
Please be respectful and constructive in all interactions. We're here to build something great together! ๐
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
- Built with โค๏ธ by Chan
- Thanks to all contributors
- Inspired by the need for simple, high-performance caching solutions
โญ If BlitzCache helped you, please consider giving it a star! โญ
Made with โก by the BlitzCache team
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. 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. |
.NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.1 is compatible. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- Microsoft.Extensions.Caching.Memory (>= 8.0.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Hosting.Abstractions (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
BlitzCache v2.1.0 - Capacity-Based Size Limit (Optional)
NEW IN v2.1.0:
โข Approximate memory usage tracking (Statistics.ApproximateMemoryBytes)
โข TopHeaviestEntries to identify largest cached items
โข Logging includes Approx. Memory and Top Heaviest sections
โข Optional maxCacheSizeBytes to enable capacity-based eviction using MemoryCache.SizeLimit
โข Automatic per-entry sizing via lightweight IValueSizer so the limit is enforced
โข Works even when statistics are disabled
โข DI: AddBlitzCache now accepts maxCacheSizeBytes
โข New tests ensuring eviction occurs and memory stays within the limit
Notes:
โข Sizing is best-effort and designed to be lightweight for common types.
โข Capacity-based eviction relies on Microsoft.Extensions.Caching.Memory heuristics.