Processor-Failure Handling
A SystemEventProcessorInterface::processEvent() call can fail — a disk full, a downstream service unreachable, a malformed custom placeholder. The System Events package makes sure that failure never propagates into the code that fired the original, unrelated event.
How Isolation Works
Both the live wildcard listener and buffered-event replay (replayInMemoryEvents()) catch Throwable around every individual processEvent() call:
- If a processor throws while handling one event, that event's failure is reported (see below) and processing continues with the next event.
- The application code that originally fired the event never sees the exception and is never interrupted by it.
This isolation lives in SystemEventsServiceProvider, not in the processor contract itself — a SystemEventProcessorInterface implementation (including FileSystemEventProcessor and CompositeSystemEventProcessor) is still free to throw; it's the provider's job to catch it.
Default Behavior
If you don't configure anything, a processor failure is reported via PHP's error_log():
[system-events] Failed to process event "payment.charged": Unable to write to log file: /var/logs/system-events.log
Custom Failure Hook
To handle failures yourself — increment a metric, forward to a monitoring service, retry against a fallback destination — pass a closure to the onProcessingFailure constructor argument of SystemEventsServiceProvider:
use DomainFlow\SystemEvents\Provider\SystemEventsServiceProvider;
use Throwable;
$app->registerProvider(new SystemEventsServiceProvider(
onProcessingFailure: function (Throwable $e, string $eventName): void {
// e.g. increment a metric, forward to a monitoring service
Metrics::increment('system_events.processing_failed', ['event' => $eventName]);
}
));
| Closure Parameter | Type | Description |
|---|---|---|
$e | Throwable | The exception thrown by processEvent(). |
$eventName | string | The name of the event that failed to process. |
💡 When
onProcessingFailureis provided, it replaces the defaulterror_log()behavior entirely — it is not called in addition to it.
Interaction with Fan-Out Processing
CompositeSystemEventProcessor aggregates every destination's failure into a single CompositeProcessingException and throws it once all configured processors have run. That exception is caught by this same isolation mechanism like any other processEvent() failure — see Fan-Out Processing for details on inspecting the individual failures it wraps.