12

I am wrapping my head around Flux Sinks and cannot understand the higher-level picture. When using Sinks.Many<T> tryEmitNext, the function tells me if there was contention and what should I do in case of failure, (FailFast/Handler).

But is there a simple construct which allows me to safely emit elements from multiple threads. For example, instead of letting the user know that there was contention and I should try again, maybe add elements to a queue(mpmc, mpsc etc), and only notify when the queue is full.

Now I can add a queue myself to alleviate the problem, but it seems a common use case. I guess I am missing a point here.

Rahul Kushwaha
  • 421
  • 7
  • 14

1 Answers1

8

I hit the same issue, migrating from Processors which support safe emission from multiple threads. I use this custom EmitFailureHandler to do a busy loop as suggested by the EmitFailureHandler docs.

public static EmitFailureHandler etryOnNonSerializedElse(EmitFailureHandler fallback){
    return (signalType, emitResult) -> {
        if (emitResult == EmitResult.FAIL_NON_SERIALIZED) {
            LockSupport.parkNanos(10);
            return true;
        } else
            return fallback.onEmitFailure(signalType, emitResult);
    };
}

There are various confusing aspects about the 3.4.0 implementation

  • There is an implication that unless the Unsafe variant is used, the sink supports serialized emission but actually all the serialized version does is to fail fast in case of concurrent emission.
  • The Sink provided by Flux.Create does support threadsafe emission.

I hope there will be a solidly engineered alternative to this offered by the library at some point.

Neil Swingler
  • 449
  • 3
  • 7
  • This solution could of course lead to 100% cpu utilization if the flux subscriber was not well behaved. A more sophisticated approach would be to block the emitting thread using e.g. a countdown latch in case of contention. Another approach would be to create a wrapper to the Sink that uses a queue in case of contention. This could be copied from https://github.com/reactor/reactor-core/blob/v3.4.1/reactor-core/src/main/java/reactor/core/publisher/FluxCreate.java#L115 – Neil Swingler Dec 21 '20 at 07:52
  • 1
    Have a look at `Sinks.many().unicast()`. It is meant to be used this way, but it should be consumed by single subscription. Maybe you can use Sinks.many().unicast() to publish to single Sinks.many().multicast()... – Lubo Oct 13 '22 at 10:30