Round #247
07 May 2026, 20:54· csharp· meta/llama-3.3-70b-instruct· r13-clean-hints
- Complexity
- band 0
- ZP / UO / OBS
- 3 / 7 / 0
- Journey weight
- 731
- Lightshift ΔL
- +0.33
Prompt
Write a circuit breaker for cache reads that falls back to the database
Zero-point index (what the engine surfaced)
ZPI-ZPI-0015 | 2026-05-07T20:54:49Z
Write a circuit breaker for cache reads that falls back to the database
ZERO POINT — 3 entries (structural invariants)
● hsl(145.55, 100%, 21%) IMemoryCache [contract]
● hsl(296.42, 100%, 27%) ResiliencePipeline [contract]
● hsl(211.57, 100%, 27%) ResiliencePipelineBuilder [contract]
UNOBSERVED — 7 entries (implied truths)
○ hsl(348.72, 100%, 22%) IDisposable [feature]
○ hsl(27.69, 100%, 50%) async [feature]
○ hsl(9.23, 100%, 32%) interface [feature]
○ hsl(180.92, 100%, 14%) Database health check [function]
○ hsl(144.00, 100%, 18%) Connection resilience [function]
○ hsl(83.08, 100%, 26%) ILogger of T injection [function]
○ hsl(49.23, 100%, 30%) try [feature]
OBSERVED — 0 entries (explicit in request)
COMPLEXITY │ 10 entries │ spread: 339° │ band: LOW
Baseline response (no ZPI)
**Circuit Breaker for Cache Reads with Database Fallback**
===========================================================
Below is an example implementation of a circuit breaker in C# that falls back to the database when cache reads fail.
### Circuit Breaker State
The circuit breaker can be in one of three states:
* **Closed**: The circuit breaker allows requests to pass through to the cache.
* **Open**: The circuit breaker prevents requests from passing through to the cache and falls back to the database.
* **Half-Open**: The circuit breaker allows a limited number of requests to pass through to the cache to test if it's working again.
### Implementation
```csharp
using System;
using System.Threading;
using System.Threading.Tasks;
public enum CircuitBreakerState
{
Closed,
Open,
HalfOpen
}
public class CacheCircuitBreaker
{
private readonly object _lock = new object();
private CircuitBreakerState _state;
private int _failureCount;
private readonly int _threshold;
private readonly TimeSpan _timeout;
private readonly TimeSpan _resetTimeout;
private readonly ICache _cache;
private readonly IDatabase _database;
public CacheCircuitBreaker(ICache cache, IDatabase database, int threshold, TimeSpan timeout, TimeSpan resetTimeout)
{
_cache = cache;
_database = database;
_threshold = threshold;
_timeout = timeout;
_resetTimeout = resetTimeout;
_state = CircuitBreakerState.Closed;
}
public async Task<T> GetAsync<T>(string key, Func<string, Task<T>> databaseFallback)
{
if (_state == CircuitBreakerState.Open)
{
// If the circuit is open, fall back to the database immediately
return await databaseFallback(key);
}
try
{
// Try to get the value from the cache
var value = await _cache.GetAsync<T>(key);
if (value != null)
{
// If the cache read is successful, reset the failure count
lock (_lock)
{
_failureCount = 0;
}
return value;
}
else
{
// If the cache read fails, increment the failure count
lock (_lock)
{
_failureCount++;
if (_failureCount >= _threshold)
{
// If the failure count exceeds the threshold, open the circuit
_state = CircuitBreakerState.Open;
Task.Delay(_resetTimeout).ContinueWith(t => ResetCircuit());
}
}
}
}
catch (Exception ex)
{
// If an exception occurs during the cache read, increment the failure count
lock (_lock)
{
_failureCount++;
if (_failureCount >= _threshold)
{
// If the failure count exceeds the threshold, open the circuit
_state = CircuitBreakerState.Open;
Task.Delay(_resetTimeout).ContinueWith(t => ResetCircuit());
}
}
throw;
}
// If the cache read fails, fall back to the database
return await databaseFallback(key);
}
private void ResetCircuit()
{
lock (_lock)
{
if (_state == CircuitBreakerState.Open)
{
_state = CircuitBreakerState.HalfOpen;
_failureCount = 0;
}
}
}
private async Task TestCacheAsync()
{
try
{
// Try to get a value from the cache to test if it's working
await _cache.GetAsync<string>("test");
lock (_lock)
{
_state = CircuitBreakerState.Closed;
}
}
catch (Exception ex)
{
lock (_lock)
{
_state = CircuitBreakerState.Open;
Task.Delay(_resetTimeout).ContinueWith(t => ResetCircuit());
}
throw;
}
}
}
public interface ICache
{
Task<T> GetAsync<T>(string key);
}
public interface IDatabase
{
Task<T> GetAsync<T>(string key);
}
```
### Example Usage
```csharp
public class Program
{
public static async Task Main(string[] args)
{
var cache = new Cache(); // Implement your cache class
var database = new Database(); // Implement your database class
var circuitBreaker = new CacheCircuitBreaker(cache, database, 3, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(30));
var value = await circuitBreaker.GetAsync<string>("key", async key => await database.GetAsync<string>(key));
Console.WriteLine(value);
}
}
```
### Notes
* The `CacheCircuitBreaker` class takes in an instance of `ICache` and `IDatabase` in its constructor.
* The `GetAsync` method tries to get a value from the cache. If the cache read fails, it falls
Enhanced response (with ZPI)
```csharp
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Polly;
using System;
using System.Threading.Tasks;
public class CacheReadCircuitBreaker
{
private readonly IMemoryCache _cache;
private readonly ILogger<CacheReadCircuitBreaker> _logger;
private readonly Policy<CacheReadResult> _policy;
public CacheReadCircuitBreaker(IMemoryCache cache, ILogger<CacheReadCircuitBreaker> logger)
{
_cache = cache;
_logger = logger;
_policy = Policy.Handle<CacheReadResult>(r => r.IsFailure)
.CircuitBreakerAsync(
exceptionsAllowedBeforeBreaking: 3,
durationOfBreak: TimeSpan.FromMinutes(1),
onBreak: (ex, ts) => _logger.LogWarning($"Cache read circuit breaker opened for {ts.TotalMinutes} minutes"),
onReset: () => _logger.LogInformation("Cache read circuit breaker closed"),
onHalfOpen: () => _logger.LogInformation("Cache read circuit breaker half-open")
);
}
public async Task<CacheReadResult> ReadAsync(string key, Func<Task<object>> databaseRead)
{
return await _policy.ExecuteAsync(async () =>
{
if (_cache.TryGetValue(key, out object cachedValue))
{
return CacheReadResult.Success(cachedValue);
}
try
{
var databaseValue = await databaseRead();
var cacheEntryOptions = new MemoryCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromHours(1));
_cache.Set(key, databaseValue, cacheEntryOptions);
return CacheReadResult.Success(databaseValue);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error reading from database");
return CacheReadResult.Failure(ex);
}
});
}
}
public class CacheReadResult
{
public bool IsFailure { get; }
public object Value { get; }
public Exception Exception { get; }
private CacheReadResult(bool isFailure, object value, Exception exception)
{
IsFailure = isFailure;
Value = value;
Exception = exception;
}
public static CacheReadResult Success(object value) => new CacheReadResult(false, value, null);
public static CacheReadResult Failure(Exception exception) => new CacheReadResult(true, null, exception);
}
```
This implementation uses the Polly library to create a circuit breaker policy for cache reads. The policy will open the circuit breaker if three consecutive cache reads fail, and will keep it open for one minute. During this time, all cache reads will fail immediately without attempting to read from the cache or database.
The `ReadAsync` method takes a key and a function to read from the database. It first checks if the value is cached, and if so, returns the cached value. If not, it attempts to read from the database and caches the result. If the database read fails, it returns a failure result.
The `CacheReadResult` class represents the result of a cache read, and can be either a success or a failure. If it's a failure, it contains the exception that occurred.
To use this class, you would create an instance of it and call the `ReadAsync` method, passing in a key and a function to read from the database. For example:
```csharp
var cacheReadCircuitBreaker = new CacheReadCircuitBreaker(cache, logger);
var result = await cacheReadCircuitBreaker.ReadAsync("key", async () => await database.ReadAsync("key"));
if (result.IsFailure)
{
_logger.LogError(result.Exception, "Error reading from cache or database");
}
else
{
var value = result.Value;
// Use the value
}
```
This code would create a circuit breaker that falls back to the database if the cache read fails, and would log any errors that occur.
Grader chain
Each grader reads the same baseline + enhanced pair and casts an independent verdict. Disagreement is the framework's own signal — not noise to be averaged away.
V1claude-haiku-4-5-20251001
BetterV4qwen2.5-coder-7b-instruct
BetterComments
Our grader said what it said. What do you say? Comment as a guest below.
No comments yet. Be the first to say what you make of this round.