UZMAN
Redis Exception Handling
StackExchange.Redis farklı hata türleri fırlatır. Doğru yakalama ve yönetim kritik.
Kod örneği görünümü
Bu sayfadaki eşleşen örnekleri seçilen istemciye göre gösterir.
Exception Tipleri
| Exception | Ne Zaman | Retry? | Aksiyon |
|---|---|---|---|
RedisConnectionException |
Bağlantı kopuk/kurulamıyor | Evet | Polly retry + circuit breaker |
RedisTimeoutException |
Komut timeout'a uğradı | Dikkatli | İlk retry, 3. tekrarda degrade |
RedisServerException |
Redis hata döndü (OOM, READONLY, WRONGTYPE) | Genelde hayır | Mesajı parse et, uygun handle |
RedisCommandException |
Komut sözdizimi/izin hatası | Hayır | Kod düzelt, ACL kontrol |
ObjectDisposedException |
Multiplexer dispose edilmiş | Hayır | Lifecycle hatası — DI kontrol |
# Timeout sorunlarını diagnose et
redis-cli --latency # ortalama latency
redis-cli --latency-history # tarihsel
redis-cli --bigkeys # büyük key'ler = yavaş ops
# Yavaş komutları logla
CONFIG SET slowlog-log-slower-than 10000 # 10ms+
SLOWLOG GET 10 # son 10 yavaş komut
SLOWLOG LEN
SLOWLOG RESET
# Memory sorunları
INFO memory
MEMORY DOCTOR
MEMORY USAGE key # tek key'in byte maliyeti
public class RedisExceptionHandler
{
private readonly IDatabase _redis;
private readonly ILogger _logger;
public RedisExceptionHandler(IConnectionMultiplexer mux, ILogger<RedisExceptionHandler> logger)
{
_redis = mux.GetDatabase();
_logger = logger;
}
public async Task<T?> ExecuteWithHandlingAsync<T>(string key, Func<IDatabase, Task<T>> operation)
{
try
{
return await operation(_redis);
}
catch (RedisConnectionException ex)
{
// Bağlantı yok — retry pipeline'a düşür veya graceful degrade
_logger.LogWarning(ex, "Redis connection failed for {Key}", key);
return default; // Fallback: DB'den oku
}
catch (RedisTimeoutException ex)
{
// Komut timeout — Redis yoğun veya big key blokaj
_logger.LogWarning(ex, "Redis timeout for {Key}. Timeout: {Timeout}ms",
key, ex.Message);
return default;
}
catch (RedisServerException ex) when (ex.Message.StartsWith("OOM"))
{
// Redis memory dolu — eviction policy'ye rağmen yazılamıyor
_logger.LogError(ex, "Redis OOM! Key: {Key}", key);
throw; // Bu ciddi — uygulama seviyesinde handle et
}
catch (RedisServerException ex) when (ex.Message.StartsWith("READONLY"))
{
// Failover sırasında — replica'ya yazma denemesi
_logger.LogWarning(ex, "Redis READONLY — failover in progress?");
await Task.Delay(1000); // Kısa bekle, yeni master keşfedilsin
return await operation(_redis); // 1 retry
}
catch (RedisServerException ex) when (ex.Message.StartsWith("WRONGTYPE"))
{
// Yanlış veri tipi — kod hatası (SET ile yazılmış, HGET ile okunuyor)
_logger.LogError(ex, "Redis WRONGTYPE for {Key} — data type mismatch", key);
throw; // Caller'ın düzeltmesi gereken bug
}
}
}
// Polly retry — StackExchange.Redis timeout'lar için önerilen strateji
builder.Services.AddResiliencePipeline("redis", builder =>
{
builder
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
Delay = TimeSpan.FromMilliseconds(200),
BackoffType = DelayBackoffType.Exponential,
ShouldHandle = new PredicateBuilder()
.Handle<RedisConnectionException>()
.Handle<RedisTimeoutException>()
})
.AddCircuitBreaker(new CircuitBreakerStrategyOptions
{
FailureRatio = 0.5,
MinimumThroughput = 10,
SamplingDuration = TimeSpan.FromSeconds(30),
BreakDuration = TimeSpan.FromSeconds(15),
ShouldHandle = new PredicateBuilder()
.Handle<RedisConnectionException>()
})
.AddTimeout(TimeSpan.FromSeconds(3));
});
Timeout tuning:
SyncTimeoutveAsyncTimeout(varsayılan 5s) çok düşük ayarlanırsa normal SCAN/SORT bile timeout alır. Çok yüksekse thread pool tıkanır. Başlangıç: 3000ms, monitoring ile ayarla.
READONLY hatası genellikle Sentinel failover sırasında olur. StackExchange.Redis otomatik yeniden bağlanır ama 1-2 saniyelik pencerede yazımlar başarısız olabilir.