Skip to main content

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 ParameterTypeDescription
$eThrowableThe exception thrown by processEvent().
$eventNamestringThe name of the event that failed to process.

💡 When onProcessingFailure is provided, it replaces the default error_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.