Spring - How to handle "IOException: Broken pipe"
An IOException
wrapped in a ClientAbortException
is thrown when a client
closes the connection while its request is still being processed in the server.
It is a little tricky to handle it in Spring MVC framework and I will explain
how to do it in this post.
Why is it tricky?
We can handle exceptions in methods annotated with @ExceptionHandler. The first thought is after handling the exception, we can return the appropriate response, right? That’s what I tried at first but it doesn’t work because the server cannot return a response, the connection is broken. So how can we tell Spring that connection is broken, don’t do anything anymore?
Solution
We don’t tell anything to framework, we are expected to know that returning null
from the method is handled magically.
@ExceptionHandler(IOException.class)
@ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE) //(1)
public Object exceptionHandler(IOException e, HttpServletRequest request) {
if (StringUtils.containsIgnoreCase(ExceptionUtils.getRootCauseMessage(e), "Broken pipe")) { //(2)
return null; //(2) socket is closed, cannot return any response
} else {
return new HttpEntity<>(e.getMessage()); //(3)
}
}
(1) Spring framework checks for status code while processing the result of the exception handler. The combination of returning null and setting response handles a broken pipe error properly.
(2) The true exception relies in the root cause, we do not want to discard every IOException
there is. Therefore we need to filter out exceptions with Broken pipe
message. To be safer, I wanted to get the message of root cause. Apache Common package has pretty nice utility methods for exceptions and we will use ExceptionUtils.getRootCauseMessage to retrieve the root cause message.
(3) As I mentioned above, we do not want to handle every IOException
there is, it is a typical code smell. The handler here should obey the single responsibility principle and it should handle only broken pipe errors.
I solved the problem just intuitively. Hope it decreases your debug time.