Norbert Bicsi
Norbert Bicsi

Reputation: 1568

Execute some action when client disconnects from hot stream

I made a simple spring boot application. I have a REST endpoint that returns a hot stream of the current time.

@RestController
public class NowResource {

    @GetMapping(value = "/now", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> now() {
        return Flux.interval(Duration.ofSeconds(1))
            .flatMap(t -> Flux.just(Instant.now().toString()));
    }

}

When I call http://localhost:8080/now I get a stream of data that looks like:

data:2018-04-03T13:20:38.313222100Z

data:2018-04-03T13:20:39.311493500Z

data:2018-04-03T13:20:40.310878800Z

...

When I disconnect from the stream (close the browser tab) an IOException is thrown, caught and the stacktrace printed.

java.io.IOException: An established connection was aborted by the software in your host machine

...

I have tried catching it but it is already caught and does not make it back to my method.

I tried adding doOnTerminate(), doOnError() etc. to the Flux but does not seem to have any effect, I'm guessing the actual event is of a different type.

Can I somehow get access to this exception to handle it differently than just printing it? (I would like to avoid have the 200+ lines of output in the log and just print "DONE" instead.)

EDIT: My solution based on the answer from Tomas Pinos

I ended up taking that approach, the difference being that I moved it to a new class and this way it handles all exceptions of this type from all controllers.

@Slf4j
@ControllerAdvice
class IOExceptionHandler implements WebExceptionHandler {

    @ExceptionHandler(IOException.class)
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        return Mono.just(ex.getMessage())
            .doOnNext(
                msg -> log.warn("IOException occurred: {}.", msg)
            )
            .then();
    }

}

Upvotes: 5

Views: 1139

Answers (1)

Tomas Pinos
Tomas Pinos

Reputation: 2862

The exception is related to HTTP connection handling between the browser ant the controller (simply put).

It can be handled in controller's @ExceptionHandler method (or in a @ControllerAdvice class, if you want to apply the same exception handling across more controllers).

For example:

@RestController
public class NowResource {
    ...

    @ExceptionHandler(IOException.class)
    public void handleException(IOException e) {
        log.warn("IOException occurred: {}", e.getMessage());
    }
}

Upvotes: 4

Related Questions