Error Recovery Module¶
Module: 04_12_error_recovery
Purpose: Comprehensive error handling and recovery strategies for production-grade audio software
Status: ✅ Complete
Overview¶
Professional audio plugins don't crash the DAW when things go wrong. They degrade gracefully, recover automatically, and provide useful diagnostics. This module provides the infrastructure for robust error handling and automatic recovery.
Module Structure¶
04_12_error_recovery/
├── 04_12_00_error_handling/ # Error definitions and handling
│ ├── error_codes.hpp # Error taxonomy (40+ predefined codes)
│ ├── result_type.hpp # Rust-style Result<T,E> monad
│ ├── error_context.hpp # Rich error context
│ └── error_handler.hpp # Central error handler
├── 04_12_01_recovery_strategies/ # Recovery mechanisms
│ ├── fallback_processor.hpp # Safe fallback processing
│ ├── circuit_breaker.hpp # Automatic feature disabling
│ └── retry_policy.hpp # Retry with exponential backoff
└── README.md # This file
Key Features¶
1. Error Code Taxonomy¶
Comprehensive error classification with categories and severity levels:
using namespace audiolab::core::error;
// Categories: Audio, System, User, Internal, Resource, State, Timing
// Severity: Info, Warning, Error, Fatal
ErrorCode err = ErrorCodes::AUDIO_BUFFER_MISMATCH;
if (err.is_fatal()) {
// Critical error handling
}
40+ Predefined Error Codes: - Audio errors (1000-1999): Buffer mismatch, device lost, sample rate issues - System errors (2000-2999): Out of memory, driver errors - Resource errors (3000-3999): Files not found, load failures - User errors (4000-4999): Invalid parameters, configuration issues - State errors (5000-5999): Invalid transitions, corruption - Internal errors (6000-6999): Assertions, null pointers - Timing errors (7000-7999): RT deadline missed, latency exceeded
2. Result Type (Exception-Free Error Propagation)¶
Rust-style Result monad for error handling without exceptions:
Result<float, ErrorCode> divide(float a, float b) {
if (b == 0.0f) {
return Result<float, ErrorCode>::err(ErrorCodes::DIVISION_BY_ZERO);
}
return Result<float, ErrorCode>::ok(a / b);
}
// Usage with chaining
auto result = divide(10.0f, 2.0f)
.map([](float x) { return x * 2; }) // Transform on success
.value_or(0.0f); // Provide default on error
Monadic Operations:
- map() - Transform success value
- and_then() - Chain operations returning Result
- or_else() - Provide alternative on error
- value_or() - Get value with fallback
3. Error Handler (Central Hub)¶
Centralized error collection and routing with RT-safe deferred reporting:
// Register custom handler
ErrorHandler::instance().register_handler(
ErrorCategory::Audio,
[](const ErrorContext& ctx) {
log_to_file(ctx.format());
}
);
// Report error (NOT RT-safe)
AUDIOLAB_REPORT_ERROR(ErrorCodes::BUFFER_OVERFLOW, "Size: 1024");
// Report from RT thread (RT-SAFE)
AUDIOLAB_REPORT_ERROR_RT(ErrorCodes::RT_DEADLINE_MISSED);
// Process deferred errors (call from GUI thread)
ErrorHandler::instance().process_deferred_errors();
Features: - Custom handler registration per category - RT-safe deferred error queue (1024 errors) - Error statistics and counting - Automatic overflow detection
4. Fallback Processor (Graceful Degradation)¶
Safe fallback processing when primary algorithm fails:
FallbackProcessor fallback;
fallback.process_with_fallback(inputs, outputs, numSamples, numChannels,
[&]() {
// Try primary processing
return reverb.process(inputs, outputs, numSamples, numChannels);
}
);
// Fallback levels: None → SafeDefault → Bypass → Silence
Fallback Hierarchy: 1. None - Normal processing 2. SafeDefault - Use safe defaults (e.g., dry signal) 3. Bypass - Pass input to output (unity gain) 4. Silence - Output silence (last resort)
5. Circuit Breaker (Automatic Disable)¶
Prevents cascading failures by disabling repeatedly failing components:
CircuitBreaker reverb_breaker(5, 5000); // 5 failures, 5s cooldown
if (reverb_breaker.allow_operation()) {
bool success = process_reverb();
reverb_breaker.record_result(success);
} else {
// Circuit open - reverb temporarily disabled
bypass_reverb();
}
// Check recovery periodically
reverb_breaker.check_recovery();
Circuit States: - Closed - Normal operation (requests allowed) - Open - Failures detected (requests blocked) - HalfOpen - Testing recovery (limited requests)
State Transitions: - Closed → Open: After N failures - Open → HalfOpen: After cooldown period - HalfOpen → Closed: On successful operation - HalfOpen → Open: On failed operation
6. Retry Policy (Exponential Backoff)¶
Automatic retry for transient failures:
RetryPolicy policy(3, 100, 2.0f); // 3 attempts, 100ms initial, 2x backoff
auto result = policy.execute([&]() -> Result<Data, ErrorCode> {
return load_resource_from_disk();
});
if (result.is_ok()) {
use_resource(result.value());
} else {
handle_persistent_failure(result.error());
}
Features: - Configurable retry attempts - Exponential backoff: delay *= multiplier - Maximum delay cap - Conditional retry (custom predicates)
Usage Examples¶
Example 1: Safe Resource Loading¶
Result<AudioFile, ErrorCode> load_audio_file(const std::string& path) {
RetryPolicy retry(3, 100);
return retry.execute([&]() -> Result<AudioFile, ErrorCode> {
std::ifstream file(path);
if (!file.is_open()) {
return Result<AudioFile, ErrorCode>::err(
ErrorCodes::RESOURCE_NOT_FOUND
);
}
AudioFile audio;
if (!audio.load(file)) {
return Result<AudioFile, ErrorCode>::err(
ErrorCodes::RESOURCE_LOAD_FAILED
);
}
return Result<AudioFile, ErrorCode>::ok(std::move(audio));
});
}
Example 2: RT-Safe Processing with Fallback¶
class SafeProcessor {
FallbackProcessor fallback_;
CircuitBreaker circuit_{5, 5000};
public:
void process(const float** inputs, float** outputs,
uint32_t numChannels, uint32_t numSamples) noexcept {
fallback_.process_with_fallback(inputs, outputs, numSamples, numChannels,
[&]() {
if (!circuit_.allow_operation()) {
return false; // Circuit open
}
bool success = try_complex_processing();
circuit_.record_result(success);
return success;
}
);
}
};
Example 3: Error Reporting with Context¶
void validate_buffer(const AudioBuffer& buf) {
if (buf.num_channels() == 0) {
AUDIOLAB_REPORT_ERROR(
ErrorCodes::INVALID_CHANNEL_COUNT,
"Buffer has zero channels"
);
return;
}
if (buf.num_samples() > MAX_BUFFER_SIZE) {
AUDIOLAB_REPORT_ERROR(
ErrorCodes::AUDIO_BUFFER_MISMATCH,
"Buffer size " + std::to_string(buf.num_samples()) +
" exceeds maximum " + std::to_string(MAX_BUFFER_SIZE)
);
return;
}
}
RT-Safety Considerations¶
RT-Safe Components ✅¶
Result<T,E>- No allocationsAUDIOLAB_REPORT_ERROR_RT()- Lock-free queueCircuitBreaker- Atomic operations onlyFallbackProcessor- No allocations
NOT RT-Safe ⚠️¶
AUDIOLAB_REPORT_ERROR()- Uses strings, locksErrorHandler::report()- Allocates, locksRetryPolicy- Usesstd::this_thread::sleep_for()ErrorHandler::register_handler()- Uses std::map
Rule: Use _RT variants in audio thread, process deferred errors on GUI thread.
Error Recovery Patterns¶
Pattern 1: Retry-Then-Fallback¶
auto result = retry_policy.execute([&]() {
return load_convolution_ir();
});
if (result.is_err()) {
fallback_processor.enter_fallback(FallbackLevel::SafeDefault);
use_algorithmic_reverb();
}
Pattern 2: Circuit Breaker + Fallback¶
if (circuit.allow_operation()) {
bool success = expensive_operation();
circuit.record_result(success);
if (!success) {
fallback_processor.enter_fallback(FallbackLevel::Bypass);
}
}
Pattern 3: Conditional Retry¶
auto result = retry_policy.execute_if(
[&]() { return network_request(); },
[](const ErrorCode& err) {
return err == ErrorCodes::TIMEOUT ||
err == ErrorCodes::RESOURCE_EXHAUSTED;
}
);
Best Practices¶
-
Always check Result before accessing value
-
Use RT-safe reporting in audio thread
-
Register error handlers during initialization
-
Use circuit breakers for external dependencies
-
Provide user-friendly error messages
Integration¶
Required Headers¶
#include "04_12_error_recovery/04_12_00_error_handling/error_codes.hpp"
#include "04_12_error_recovery/04_12_00_error_handling/result_type.hpp"
#include "04_12_error_recovery/04_12_00_error_handling/error_handler.hpp"
#include "04_12_error_recovery/04_12_01_recovery_strategies/fallback_processor.hpp"
#include "04_12_error_recovery/04_12_01_recovery_strategies/circuit_breaker.hpp"
#include "04_12_error_recovery/04_12_01_recovery_strategies/retry_policy.hpp"
Namespace¶
Error Code Reference¶
See error_codes.hpp for complete list of 40+ predefined error codes.
Quick Reference:
- SUCCESS (0) - Operation succeeded
- AUDIO_BUFFER_MISMATCH (1001) - Buffer size mismatch
- OUT_OF_MEMORY (2001) - Memory allocation failed
- RESOURCE_NOT_FOUND (3001) - Resource not found
- INVALID_PARAMETER (4001) - Parameter out of range
- STATE_CORRUPTION (5002) - Plugin state corrupted
- DIVISION_BY_ZERO (6003) - Division by zero
- RT_DEADLINE_MISSED (7001) - RT deadline missed
- MAX_RETRIES_EXCEEDED (8001) - All retry attempts failed
See Also¶
- Error Codes - Complete error taxonomy
- Result Type - Monadic error handling
- Circuit Breaker - Fault isolation
- Retry Policy - Automatic retry