recoveryMiddleware function
Middleware that provides error recovery functionality.
This middleware catches any errors that occur during the execution of the next middleware in the chain. If an error occurs, it checks if the error is related to a broken pipe or connection reset. If it is not, it logs the error and stack trace, and then calls the provided recovery handler. If no custom handler is provided, a default handler is used.
If the error is related to a broken pipe or connection reset, the middleware quietly aborts the context without logging or calling the handler.
Implementation
Middleware recoveryMiddleware({RecoveryHandler? handler}) {
handler ??= _defaultRecoveryHandler;
return (EngineContext ctx, Next next) async {
try {
return await next();
} catch (error, stackTrace) {
final isBrokenPipe = _isBrokenPipeError(error);
if (!isBrokenPipe) {
final trace = Trace.from(stackTrace).terse;
// print suppressed in tests; could route to logger
// print('[Recovery] ${DateTime.now()}: $error\n$trace');
final enrichedStack = StackTrace.fromString(
'Route: ${ctx.request.uri.path}\n${trace.toString()}',
);
handler!(ctx, error, enrichedStack);
// Send the default JSON response only if the handler hasn't already
// completed / closed the context.
final handled = ctx.get<bool>(_recoveryHandledKey) ?? false;
if (!ctx.isClosed && !handled) {
ctx.set(_recoveryHandledKey, true);
return ctx.json({
'error': 'Internal Server Error',
}, statusCode: HttpStatus.internalServerError);
}
// The response has already been handled inside the custom recovery
// handler, so we simply return the current response.
return ctx.response;
} else {
ctx.abort();
return ctx.string('', statusCode: HttpStatus.internalServerError);
}
}
};
}