Files
michaelschiemer/src/Framework/ErrorBoundaries/Async

Async ErrorBoundary System

Complete async error boundary implementation using the framework's async components (FiberManager, AsyncPromise, etc.).

Components

Core Classes

  • AsyncErrorBoundary - Main async error boundary using framework's FiberManager and AsyncPromise
  • AsyncErrorBoundaryFactory - Factory for creating async boundaries with different configurations
  • AsyncBulkResult - Result object for batch async operations with success/error tracking
  • AsyncBoundaryFailedException - Exception for when both operation and fallback fail
  • AsyncCircuitBreakerOpenException - Exception for circuit breaker open state

Framework Integration

Uses Framework Async Components

  • FiberManager - Fiber-based async execution with batching and throttling
  • AsyncPromise - Promise-based async/await pattern
  • Clock/Timer - Time management using framework value objects
  • Duration/Timestamp - Proper time value objects

ErrorBoundary Integration

  • Circuit breaker state management via BoundaryCircuitBreakerManager
  • Event publishing via BoundaryEventPublisher
  • Metrics and observability support
  • Same retry strategies and configuration as sync boundaries

Usage Examples

Basic Async Operation

$factory = new AsyncErrorBoundaryFactory($fiberManager, $clock, $timer);
$boundary = $factory->createForExternalService('payment_api');

$promise = $boundary->executeAsync(
    operation: fn() => $paymentApi->processPayment($request),
    fallback: fn() => $this->createOfflinePaymentRecord($request)
);

$result = $promise->await();

Concurrent Operations

$operations = [
    'user_data' => fn() => $userService->getUserData($userId),
    'preferences' => fn() => $preferenceService->getPreferences($userId),
    'notifications' => fn() => $notificationService->getUnread($userId),
];

$promise = $boundary->executeConcurrent($operations);
$results = $promise->await();

// Results: ['user_data' => ..., 'preferences' => ..., 'notifications' => ...]

Batch Processing

$batchBoundary = $factory->createForBatchProcessing('email_sending');

$promise = $batchBoundary->executeBatch(
    items: $emailQueue,
    processor: fn($email) => $mailService->send($email),
    maxConcurrency: 5
);

$bulkResult = $promise->await();

echo "Success rate: " . $bulkResult->getSuccessRate()->toFloat() * 100 . "%\n";
echo "Processed: {$bulkResult->successfulOperations}/{$bulkResult->totalOperations}\n";

Timeout Handling

$promise = $boundary->executeWithTimeout(
    operation: fn() => $heavyComputation->process($data),
    timeout: Duration::fromSeconds(30),
    fallback: fn() => $this->getCachedResult($data)
);

try {
    $result = $promise->await();
} catch (AsyncTimeoutException $e) {
    // Handle timeout
}

Circuit Breaker with Async

$promise = $boundary->executeWithCircuitBreaker(
    operation: fn() => $externalApi->call($request),
    fallback: fn() => $this->getDefaultResponse()
);

$result = $promise->await();

Factory Configurations

External Service Boundary

$boundary = $factory->createForExternalService('payment_service');
  • Retry strategy with exponential backoff
  • Circuit breaker enabled
  • Appropriate timeouts for external calls

Database Boundary

$boundary = $factory->createForDatabase('user_queries');
  • Fast fail for database issues
  • Connection pooling aware
  • Optimized for database operation patterns

Background Job Boundary

$boundary = $factory->createForBackgroundJob('email_processor');
  • Higher retry counts
  • Longer timeouts
  • Batch error tolerance

High Throughput Boundary

$boundary = $factory->createForHighThroughput('api_endpoints');
  • Minimal retries for speed
  • Higher circuit breaker thresholds
  • Optimized for high-volume operations

Async Result Types

AsyncBulkResult

$bulkResult = $promise->await();

// Statistics
$successRate = $bulkResult->getSuccessRate(); // Percentage object
$errorRate = $bulkResult->getErrorRate();     // Percentage object

// Individual results
$userResult = $bulkResult->getResult('user_1');
$userError = $bulkResult->getError('user_1');

// Status checks
$hasAnyErrors = $bulkResult->hasErrors();
$isCompleteSuccess = $bulkResult->isCompleteSuccess();

Event Integration

Async boundaries publish the same events as sync boundaries:

  • BoundaryExecutionSucceeded - Successful async operation
  • BoundaryExecutionFailed - Failed async operation
  • BoundaryFallbackExecuted - Fallback was used
  • BoundaryTimeoutOccurred - Operation timed out

Promise Chaining

$promise = $boundary->executeAsync(fn() => $service->getData())
    ->then(fn($data) => $this->processData($data))
    ->then(fn($processed) => $this->saveData($processed))
    ->catch(fn($error) => $this->handleError($error))
    ->finally(fn() => $this->cleanup());

$result = $promise->await();

Concurrent with Fallbacks

$operations = [
    'primary_data' => fn() => $primaryService->getData(),
    'backup_data' => fn() => $backupService->getData(),
];

$fallbacks = [
    'primary_data' => fn() => $cache->get('primary_data'),
    'backup_data' => fn() => $cache->get('backup_data'),
];

$promise = $boundary->executeConcurrent($operations, $fallbacks);
$results = $promise->await();

Health Monitoring

// Async health check
$healthPromise = $boundary->getCircuitHealthAsync();
$health = $healthPromise->await();

if ($health && !$health['is_healthy']) {
    $this->alerting->sendAlert("Boundary {$boundary->boundaryName} is unhealthy");
}

// Async circuit reset
$resetPromise = $boundary->resetCircuitAsync();
$resetPromise->await();

Performance Benefits

Framework Integration Benefits

  • Fiber-based: Uses PHP 8.1+ Fibers for true async execution
  • Batching: Framework's FiberManager handles optimal batching
  • Throttling: Built-in concurrency control
  • Timeout Management: Framework's timeout handling with proper cleanup

Error Boundary Benefits

  • Graceful Degradation: Async fallbacks prevent service interruption
  • Circuit Breaking: Prevents cascade failures in async operations
  • Retry Logic: Async retry with proper delays
  • Observability: Events and metrics for async operations

Best Practices

Concurrency Management

// Good: Use factory methods for appropriate concurrency
$batchBoundary = $factory->createForBatchProcessing('data_sync');
$bulkResult = $batchBoundary->executeBatch($items, $processor, 10);

// Good: Throttle concurrent operations  
$results = $fiberManager->throttled($operations, 5);

Error Handling

// Good: Provide meaningful fallbacks
$promise = $boundary->executeAsync(
    operation: fn() => $externalService->getData(),
    fallback: fn() => $this->getCachedData() // Always have a fallback
);

// Good: Handle different error types
try {
    $result = $promise->await();
} catch (AsyncCircuitBreakerOpenException $e) {
    // Circuit breaker is open
} catch (AsyncBoundaryFailedException $e) {
    // Both operation and fallback failed
    $originalError = $e->getOriginalException();
    $fallbackError = $e->getFallbackException();
}

Performance Optimization

// Good: Use appropriate configurations
$highThroughputBoundary = $factory->createForHighThroughput('api_calls');
$batchBoundary = $factory->createForBatchProcessing('data_processing');

// Good: Monitor performance
$bulkResult = $batchBoundary->executeBatch($items, $processor);
$this->metrics->record('batch_success_rate', $bulkResult->getSuccessRate());