2

Per here I used to have code

EmitterProcessor<String> emitter = EmitterProcessor.create();
FluxSink<String> sink = emitter.sink(FluxSink.OverflowStrategy.LATEST);

sink.onCancel(() -> {
  cancelSink(id, request);
});

and when for example with rSocket a browser opened a session and asked for some data, calling the EmitterProcessor when a client shut down their browser the publisher like

Flux<String> out = Flux
    .from(emitter
    .log(log.getName())); 

would know that the Flux subscriber was cancelled (when a browser was closed) and that would call the onCancel handle.

With Sinks.Many() I have implemented

Many<String> sink = Sinks.many().unicast().onBackpressureBuffer();

sink.asFlux().doOnCancel(() -> {
    cancelSink(id, request);
});

Flux<String> out = Flux
    .from(sink.asFlux()
    .log(log.getName()));

and the strings are published via a flux to the browser, but when the client closes the session there is no longer the onCancel to handle some tidying up.

It looks like this was discussed here and also here but I don't understand the solutions. What is it please?

rupweb
  • 3,052
  • 1
  • 30
  • 57

1 Answers1

3

sink.asFlux().doOnCancel(...) and sink.asFlux() are two different instances. You're not reusing the one where you have set up cancel handling logic, and that is why you don't observe the cancelSink cleanup on your out variable.

Do something more like:

Many<String> sink = Sinks.many().unicast().onBackpressureBuffer();

Flux<String> fluxWithCancelSupport = sink.asFlux().doOnCancel(() -> {
    cancelSink(id, request);
});

Flux<String> out = fluxWithCancelSupport
    .log(log.getName()));

(PS: you don't need the Flux.from(sink.asFlux()) since the later already gives you a Flux).

Simon Baslé
  • 27,105
  • 5
  • 69
  • 70
  • Thanks, so the use case is to use the sink (or flux?) to send out random updates coming from another queue. It was using `tryEmitNext(String)` to emit (or publish?) the queue message out to the flux subscriber. Is there a `Flux` equivalent to `tryEmitNext` as used by `Many` sink ? Thanks... – rupweb Mar 31 '21 at 09:05
  • Or, as i have done now, is a recommended approach to use the sink `tryEmitNext` to handle the queue *and then* cast `asFlux` to publish back to the caller... – rupweb Mar 31 '21 at 09:22
  • 1
    I think the second approach, if I understand it correctly. My answer just meant to say that your snippet basically ignores the result of `sink.asFlux().doOnCancel(...)`, so the runnable in there will never be invoked. – Simon Baslé Mar 31 '21 at 13:09
  • yes, thank's that's great i have the flow kind of working now, but I have run into [this](https://stackoverflow.com/questions/66888735/in-reactor-flux-an-oncancel-call-is-not-returned-to-calling-method) i am still missing something about flux lifecycles? – rupweb Mar 31 '21 at 13:22
  • all implementations of asFlux() will return same instance of flux. So first sentence of this answer is not correct. Other side is, that this should be done using `flux = sink.asFlux; flux....` – Lubo Oct 13 '22 at 07:54