Reputation: 7807
I have a Spring Rest Controller that returns millions of rows in a SpringBoot application.
@GetMapping(value = "/getStreamOfJson")
public void getStreamOfJson(HttpServletResponse resp) throws IOException, InterruptedException {
resp.setContentType("text/plain");
resp.setBufferSize(1024);
try (PrintWriter pw = resp.getWriter()) {
for (int i = 0; i < 100_000_000; ++i) {
GenericDto dto = GenericDto.builder()
.id(i)
.desc("DTO#%d".formatted(i))
.build();
String str = objectMapper.writeValueAsString(dto);
logger.debug("getStreamOfJson: {}", str);
pw.println(str);
pw.flush(); // added just with the hope to receive the exception earlier
}
}
}
Then I try to consume it with curl
or a Spring WebClient.
BUT when I terminate the client in the middle of the reading, the server continues to write data till the end and does not receive the SocketException: Borken Pipe
or any other exception.
The ApplicationServer used by Spring in my example is Tomcat.
Why I'm not receiving any Exception when the client is terminated? How can I receive it?
Upvotes: 0
Views: 38
Reputation: 7807
A silly question on my part.
I forgot that, as also mentioned in the documentation (https://docs.oracle.com/javase/8/docs/api/java/io/PrintWriter.html), the PrintWriter
class, unlike the Writer
class from which it inherits, behaves differently:
Methods in this class never throw I/O exceptions, although some of its constructors may. The client may inquire as to whether any errors have occurred by invoking
checkError()
.
So I added that check in my loop
for (int i = 0; i < N; ++i) {
if (pw.checkError()) {
logger.warn("Response is closed");
return;
}
...
And now everything works fine.
Upvotes: 1