The Firefly EDA library supports custom error handling strategies that allow you to implement your own error handling logic for event listeners.
When you set the error handling strategy to CUSTOM in your @EventListener annotation, the library will delegate error handling to registered custom error handlers instead of using the built-in strategies.
@EventListener(
eventType = OrderCreatedEvent.class,
errorHandling = ErrorHandlingStrategy.CUSTOM
)
public void handleOrderCreated(OrderCreatedEvent event) {
// Your event handling logic
if (someCondition) {
throw new RuntimeException("Something went wrong");
}
}@Component
public class MyCustomErrorHandler implements CustomErrorHandler {
@Override
public Mono<Void> handleError(Object event, Map<String, Object> headers,
Throwable error, String listenerMethod) {
return Mono.fromRunnable(() -> {
// Your custom error handling logic
log.error("Custom error handling for {}: {}", listenerMethod, error.getMessage());
// Send notifications, create tickets, etc.
notificationService.sendAlert(error, event);
});
}
@Override
public String getHandlerName() {
return "my-custom-handler";
}
@Override
public boolean canHandle(Class<? extends Throwable> errorType) {
// Only handle specific error types
return RuntimeException.class.isAssignableFrom(errorType);
}
@Override
public int getPriority() {
return 100; // Higher numbers = higher priority
}
}The library includes several built-in custom error handlers that you can enable:
Sends notifications for critical errors.
Configuration:
firefly:
eda:
error:
notification:
enabled: trueFeatures:
- Handles
RuntimeException,IllegalStateException, andSecurityException - Differentiates between critical and warning alerts
- High priority (100)
Records error metrics for monitoring and observability.
Configuration:
firefly:
eda:
error:
metrics:
enabled: true # Default: trueFeatures:
- Records error counts by listener method and error type
- Records error processing duration
- Integrates with Micrometer metrics
- Medium priority (50)
You can implement selective error handling based on error types:
@Override
public boolean canHandle(Class<? extends Throwable> errorType) {
// Only handle database-related errors
return SQLException.class.isAssignableFrom(errorType) ||
DataAccessException.class.isAssignableFrom(errorType);
}Multiple custom error handlers are executed in priority order (highest first):
@Override
public int getPriority() {
return 200; // Very high priority
}You can register error handlers programmatically:
@Autowired
private CustomErrorHandlerRegistry errorHandlerRegistry;
public void registerMyHandler() {
CustomErrorHandler handler = new MyDynamicErrorHandler();
errorHandlerRegistry.registerHandler(handler);
}- Discovery: Custom error handlers are automatically discovered as Spring beans
- Registration: Handlers are registered and sorted by priority during startup
- Execution: When a CUSTOM error strategy is triggered:
- All applicable handlers (based on
canHandle()) are identified - Handlers are executed in priority order
- Each handler runs independently (failures don't affect others)
- All handlers complete before the error handling finishes
- All applicable handlers (based on
@Override
public Mono<Void> handleError(Object event, Map<String, Object> headers,
Throwable error, String listenerMethod) {
return Mono.fromRunnable(() -> {
try {
// Your error handling logic
performErrorHandling(event, error);
} catch (Exception e) {
// Don't let handler errors propagate
log.warn("Error handler failed", e);
}
});
}- Critical handlers (notifications, alerts): 100-200
- Monitoring handlers (metrics, logging): 50-99
- Cleanup handlers (resource cleanup): 1-49
@Override
public boolean canHandle(Class<? extends Throwable> errorType) {
// Use efficient type checking
return HANDLED_TYPES.stream()
.anyMatch(type -> type.isAssignableFrom(errorType));
}
private static final Set<Class<? extends Throwable>> HANDLED_TYPES = Set.of(
RuntimeException.class,
IllegalStateException.class,
SecurityException.class
);@Override
public String getHandlerName() {
return "order-processing-error-handler";
}firefly:
eda:
error:
custom:
enabled: true # Default: truefirefly:
eda:
error:
notification:
enabled: true
critical-threshold: ERROR
metrics:
enabled: true
detailed-timing: trueIf you see this warning:
CUSTOM error strategy specified but no custom error handlers available, falling back to LOG_AND_CONTINUE
Solutions:
- Ensure your custom error handler is annotated with
@Component - Verify the handler is in a package scanned by Spring
- Check that the handler implements
CustomErrorHandlercorrectly
Check:
- The
canHandle()method returnstruefor your error type - The handler is properly registered (check logs during startup)
- The error handling strategy is set to
CUSTOM
Optimize:
- Keep error handling logic lightweight
- Use async operations for heavy processing
- Implement efficient error type checking
- Consider handler priorities to avoid unnecessary processing