🔷 🛑 Error Handling Patterns - TuskLang for C# - "Resilience Mastery"
🛑 Error Handling Patterns - TuskLang for C# - "Resilience Mastery"
Master error handling patterns with TuskLang in your C# applications!
Error handling is crucial for building resilient applications. This guide covers exception handling, error recovery, circuit breakers, and real-world error handling scenarios for TuskLang in C# environments.
🛡️ Error Handling Philosophy
"We Don't Bow to Any King"
- Fail gracefully - Never crash, always recover - Fail fast - Detect errors early - Retry intelligently - Use exponential backoff - Circuit breakers - Prevent cascading failures - Monitor everything - Track error patterns🔄 Exception Handling
Example: Exception Handling Service
// ExceptionHandlingService.cs
public class ExceptionHandlingService
{
private readonly TuskLang _parser;
private readonly ILogger<ExceptionHandlingService> _logger;
private readonly Dictionary<string, ExceptionHandler> _exceptionHandlers;
public ExceptionHandlingService(ILogger<ExceptionHandlingService> logger)
{
_parser = new TuskLang();
_logger = logger;
_exceptionHandlers = new Dictionary<string, ExceptionHandler>();
RegisterExceptionHandlers();
}
private void RegisterExceptionHandlers()
{
// Register database exception handler
_exceptionHandlers["DatabaseException"] = new ExceptionHandler
{
ExceptionType = typeof(SqlException),
RetryCount = 3,
RetryDelay = TimeSpan.FromSeconds(1),
FallbackAction = () => new Dictionary<string, object> { ["error"] = "Database temporarily unavailable" }
};
// Register network exception handler
_exceptionHandlers["NetworkException"] = new ExceptionHandler
{
ExceptionType = typeof(HttpRequestException),
RetryCount = 2,
RetryDelay = TimeSpan.FromSeconds(2),
FallbackAction = () => new Dictionary<string, object> { ["error"] = "Network temporarily unavailable" }
};
// Register validation exception handler
_exceptionHandlers["ValidationException"] = new ExceptionHandler
{
ExceptionType = typeof(ValidationException),
RetryCount = 0,
RetryDelay = TimeSpan.Zero,
FallbackAction = () => new Dictionary<string, object> { ["error"] = "Invalid input data" }
};
_logger.LogInformation("Registered {Count} exception handlers", _exceptionHandlers.Count);
}
public async Task<T> ExecuteWithErrorHandlingAsync<T>(Func<Task<T>> operation, string operationName)
{
try
{
_logger.LogDebug("Executing operation: {OperationName}", operationName);
var result = await operation();
_logger.LogDebug("Operation {OperationName} completed successfully", operationName);
return result;
}
catch (Exception ex)
{
var handler = GetExceptionHandler(ex);
if (handler != null)
{
return await HandleExceptionWithRetryAsync(operation, handler, operationName);
}
_logger.LogError(ex, "Unhandled exception in operation {OperationName}", operationName);
throw;
}
}
private ExceptionHandler? GetExceptionHandler(Exception exception)
{
foreach (var handler in _exceptionHandlers.Values)
{
if (handler.ExceptionType.IsInstanceOfType(exception))
{
return handler;
}
}
return null;
}
private async Task<T> HandleExceptionWithRetryAsync<T>(Func<Task<T>> operation, ExceptionHandler handler, string operationName)
{
for (int attempt = 1; attempt <= handler.RetryCount; attempt++)
{
try
{
_logger.LogWarning("Retry attempt {Attempt} for operation {OperationName}", attempt, operationName);
await Task.Delay(handler.RetryDelay * attempt); // Exponential backoff
var result = await operation();
_logger.LogInformation("Operation {OperationName} succeeded on retry attempt {Attempt}", operationName, attempt);
return result;
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Retry attempt {Attempt} failed for operation {OperationName}", attempt, operationName);
if (attempt == handler.RetryCount)
{
_logger.LogError(ex, "All retry attempts failed for operation {OperationName}, using fallback", operationName);
return (T)handler.FallbackAction();
}
}
}
return (T)handler.FallbackAction();
}
}public class ExceptionHandler
{
public Type ExceptionType { get; set; } = typeof(Exception);
public int RetryCount { get; set; }
public TimeSpan RetryDelay { get; set; }
public Func<object> FallbackAction { get; set; } = () => new { error = "Operation failed" };
}
public class ValidationException : Exception
{
public ValidationException(string message) : base(message) { }
}
🔌 Circuit Breaker Pattern
Example: Circuit Breaker Service
// CircuitBreakerService.cs
public class CircuitBreakerService
{
private readonly TuskLang _parser;
private readonly ILogger<CircuitBreakerService> _logger;
private readonly Dictionary<string, CircuitBreaker> _circuitBreakers;
public CircuitBreakerService(ILogger<CircuitBreakerService> logger)
{
_parser = new TuskLang();
_logger = logger;
_circuitBreakers = new Dictionary<string, CircuitBreaker>();
LoadCircuitBreakerConfiguration();
}
private void LoadCircuitBreakerConfiguration()
{
var config = _parser.ParseFile("config/circuit-breakers.tsk");
var breakers = config["circuit_breakers"] as Dictionary<string, object>;
foreach (var breaker in breakers ?? new Dictionary<string, object>())
{
var breakerName = breaker.Key;
var breakerConfig = breaker.Value as Dictionary<string, object>;
if (breakerConfig != null)
{
_circuitBreakers[breakerName] = new CircuitBreaker
{
Name = breakerName,
FailureThreshold = int.Parse(breakerConfig["failure_threshold"].ToString()),
RecoveryTimeout = TimeSpan.FromSeconds(int.Parse(breakerConfig["recovery_timeout_seconds"].ToString())),
MonitoringWindow = TimeSpan.FromSeconds(int.Parse(breakerConfig["monitoring_window_seconds"].ToString()))
};
}
}
_logger.LogInformation("Loaded {Count} circuit breaker configurations", _circuitBreakers.Count);
}
public async Task<T> ExecuteWithCircuitBreakerAsync<T>(string breakerName, Func<Task<T>> operation)
{
if (!_circuitBreakers.ContainsKey(breakerName))
{
_logger.LogWarning("Circuit breaker {BreakerName} not found, executing without circuit breaker", breakerName);
return await operation();
}
var circuitBreaker = _circuitBreakers[breakerName];
switch (circuitBreaker.State)
{
case CircuitBreakerState.Closed:
return await ExecuteInClosedStateAsync(circuitBreaker, operation);
case CircuitBreakerState.Open:
return await ExecuteInOpenStateAsync(circuitBreaker, operation);
case CircuitBreakerState.HalfOpen:
return await ExecuteInHalfOpenStateAsync(circuitBreaker, operation);
default:
throw new InvalidOperationException($"Unknown circuit breaker state: {circuitBreaker.State}");
}
}
private async Task<T> ExecuteInClosedStateAsync<T>(CircuitBreaker circuitBreaker, Func<Task<T>> operation)
{
try
{
var result = await operation();
circuitBreaker.RecordSuccess();
return result;
}
catch (Exception ex)
{
circuitBreaker.RecordFailure();
_logger.LogWarning(ex, "Operation failed in closed state for circuit breaker {BreakerName}", circuitBreaker.Name);
throw;
}
}
private async Task<T> ExecuteInOpenStateAsync<T>(CircuitBreaker circuitBreaker, Func<Task<T>> operation)
{
if (circuitBreaker.ShouldAttemptReset())
{
_logger.LogInformation("Attempting to reset circuit breaker {BreakerName}", circuitBreaker.Name);
circuitBreaker.SetHalfOpen();
return await ExecuteInHalfOpenStateAsync(circuitBreaker, operation);
}
_logger.LogWarning("Circuit breaker {BreakerName} is open, returning fallback", circuitBreaker.Name);
return (T)circuitBreaker.FallbackAction();
}
private async Task<T> ExecuteInHalfOpenStateAsync<T>(CircuitBreaker circuitBreaker, Func<Task<T>> operation)
{
try
{
var result = await operation();
circuitBreaker.SetClosed();
_logger.LogInformation("Circuit breaker {BreakerName} reset to closed state", circuitBreaker.Name);
return result;
}
catch (Exception ex)
{
circuitBreaker.SetOpen();
_logger.LogWarning(ex, "Operation failed in half-open state for circuit breaker {BreakerName}", circuitBreaker.Name);
return (T)circuitBreaker.FallbackAction();
}
}
public async Task<Dictionary<string, object>> GetCircuitBreakerStatusAsync()
{
var status = new Dictionary<string, object>();
foreach (var breaker in _circuitBreakers)
{
status[breaker.Key] = new Dictionary<string, object>
{
["state"] = breaker.Value.State.ToString(),
["failure_count"] = breaker.Value.FailureCount,
["last_failure_time"] = breaker.Value.LastFailureTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? "Never",
["next_reset_time"] = breaker.Value.NextResetTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? "N/A"
};
}
return status;
}
}public class CircuitBreaker
{
public string Name { get; set; } = string.Empty;
public CircuitBreakerState State { get; private set; } = CircuitBreakerState.Closed;
public int FailureCount { get; private set; }
public int FailureThreshold { get; set; }
public TimeSpan RecoveryTimeout { get; set; }
public TimeSpan MonitoringWindow { get; set; }
public DateTime? LastFailureTime { get; private set; }
public DateTime? NextResetTime { get; private set; }
public void RecordSuccess()
{
if (State == CircuitBreakerState.Closed)
{
FailureCount = 0;
LastFailureTime = null;
}
}
public void RecordFailure()
{
FailureCount++;
LastFailureTime = DateTime.UtcNow;
if (FailureCount >= FailureThreshold)
{
SetOpen();
}
}
public void SetOpen()
{
State = CircuitBreakerState.Open;
NextResetTime = DateTime.UtcNow.Add(RecoveryTimeout);
_logger.LogWarning("Circuit breaker {Name} opened after {FailureCount} failures", Name, FailureCount);
}
public void SetHalfOpen()
{
State = CircuitBreakerState.HalfOpen;
NextResetTime = null;
}
public void SetClosed()
{
State = CircuitBreakerState.Closed;
FailureCount = 0;
LastFailureTime = null;
NextResetTime = null;
}
public bool ShouldAttemptReset()
{
return State == CircuitBreakerState.Open &&
NextResetTime.HasValue &&
DateTime.UtcNow >= NextResetTime.Value;
}
public object FallbackAction()
{
return new Dictionary<string, object> { ["error"] = $"Service {Name} temporarily unavailable" };
}
}
public enum CircuitBreakerState
{
Closed,
Open,
HalfOpen
}
🔄 Retry Pattern
Example: Retry Service
// RetryService.cs
public class RetryService
{
private readonly TuskLang _parser;
private readonly ILogger<RetryService> _logger;
private readonly Dictionary<string, RetryPolicy> _retryPolicies;
public RetryService(ILogger<RetryService> logger)
{
_parser = new TuskLang();
_logger = logger;
_retryPolicies = new Dictionary<string, RetryPolicy>();
LoadRetryPolicies();
}
private void LoadRetryPolicies()
{
var config = _parser.ParseFile("config/retry-policies.tsk");
var policies = config["retry_policies"] as Dictionary<string, object>;
foreach (var policy in policies ?? new Dictionary<string, object>())
{
var policyName = policy.Key;
var policyData = policy.Value as Dictionary<string, object>;
if (policyData != null)
{
_retryPolicies[policyName] = new RetryPolicy
{
Name = policyName,
MaxRetries = int.Parse(policyData["max_retries"].ToString()),
BaseDelay = TimeSpan.FromMilliseconds(int.Parse(policyData["base_delay_ms"].ToString())),
MaxDelay = TimeSpan.FromSeconds(int.Parse(policyData["max_delay_seconds"].ToString())),
BackoffMultiplier = double.Parse(policyData["backoff_multiplier"].ToString())
};
}
}
_logger.LogInformation("Loaded {Count} retry policies", _retryPolicies.Count);
}
public async Task<T> ExecuteWithRetryAsync<T>(string policyName, Func<Task<T>> operation)
{
if (!_retryPolicies.ContainsKey(policyName))
{
_logger.LogWarning("Retry policy {PolicyName} not found, executing without retry", policyName);
return await operation();
}
var policy = _retryPolicies[policyName];
var delay = policy.BaseDelay;
for (int attempt = 0; attempt <= policy.MaxRetries; attempt++)
{
try
{
if (attempt > 0)
{
_logger.LogInformation("Retry attempt {Attempt} for policy {PolicyName}", attempt, policyName);
await Task.Delay(delay);
}
var result = await operation();
if (attempt > 0)
{
_logger.LogInformation("Operation succeeded on retry attempt {Attempt} for policy {PolicyName}", attempt, policyName);
}
return result;
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Operation failed on attempt {Attempt} for policy {PolicyName}", attempt, policyName);
if (attempt == policy.MaxRetries)
{
_logger.LogError(ex, "All retry attempts failed for policy {PolicyName}", policyName);
throw;
}
// Calculate next delay with exponential backoff
delay = TimeSpan.FromMilliseconds(Math.Min(
delay.TotalMilliseconds * policy.BackoffMultiplier,
policy.MaxDelay.TotalMilliseconds
));
}
}
throw new InvalidOperationException($"Retry policy {policyName} failed unexpectedly");
}
}public class RetryPolicy
{
public string Name { get; set; } = string.Empty;
public int MaxRetries { get; set; }
public TimeSpan BaseDelay { get; set; }
public TimeSpan MaxDelay { get; set; }
public double BackoffMultiplier { get; set; }
}
🛠️ Real-World Error Handling Scenarios
- Database operations: Handle connection failures and timeouts - API calls: Handle network failures and service unavailability - File operations: Handle file system errors and permissions - External services: Handle third-party service failures🧩 Best Practices
- Use appropriate retry strategies - Implement circuit breakers for external dependencies - Log errors with sufficient context - Provide meaningful error messages - Monitor error patterns and trends🏁 You're Ready!
You can now: - Implement comprehensive error handling - Use circuit breakers for resilience - Apply retry patterns with exponential backoff - Build robust, fault-tolerant applications
Next: Logging Patterns
---
"We don't bow to any king" - Your resilience mastery, your fault tolerance, your error excellence.
Handle errors gracefully. Recover confidently. 🛑