/** * Connects this {@link ConnectableFlux} to the upstream source when the first {@link org.reactivestreams.Subscriber} * subscribes. * * <p> * <img class="marble" src="doc-files/marbles/autoConnect.svg" alt=""> * * @return a {@link Flux} that connects to the upstream source when the first {@link org.reactivestreams.Subscriber} subscribes */ public final Flux<T> autoConnect() { return autoConnect(1); }
/** * Connects to the upstream source when the first {@link org.reactivestreams.Subscriber} subscribes and disconnects * when all Subscribers cancelled or the upstream source completed. * * <p> * <img class="marble" src="doc-files/marbles/refCount.svg" alt=""> * * @return a reference counting {@link Flux} */ public final Flux<T> refCount() { return refCount(1); }
/** * Connects this {@link ConnectableFlux} to the upstream source when the specified amount of * {@link org.reactivestreams.Subscriber} subscribes and calls the supplied consumer with a runnable that allows disconnecting. * <p> * <img class="marble" src="doc-files/marbles/autoConnectWithMinSubscribers.svg" alt=""> * * @param minSubscribers the minimum number of subscribers * @param cancelSupport the consumer that will receive the {@link Disposable} that allows disconnecting * @return a {@link Flux} that connects to the upstream source when the given amount of subscribers subscribed */ public final Flux<T> autoConnect(int minSubscribers, Consumer<? super Disposable> cancelSupport) { if (minSubscribers == 0) { connect(cancelSupport); return this; } if(this instanceof Fuseable){ return onAssembly(new FluxAutoConnectFuseable<>(this, minSubscribers, cancelSupport)); } return onAssembly(new FluxAutoConnect<>(this, minSubscribers, cancelSupport)); }
Flux<T> fluxToUse = connectableFlux.doOnSubscribe(subscription -> { disposable = connectableFlux.connect();
@Override protected List<Scenario<String, String>> scenarios_operatorSuccess() { return Arrays.asList( scenario(f -> f.publish().autoConnect()), scenario(f -> f.publish().refCount()) ); }
/** * Connect this {@link ConnectableFlux} to its source and return a {@link Runnable} that * can be used for disconnecting. * @return the {@link Disposable} that allows disconnecting the connection after. */ public final Disposable connect() { final Disposable[] out = { null }; connect(r -> out[0] = r); return out[0]; }
@Test public void testMultiReceiver() throws Exception { Hooks.onOperatorDebug(); try { ConnectableFlux<?> t = Flux.empty() .then(Mono.defer(() -> { throw new RuntimeException(); })).flux().publish(); t.map(d -> d).subscribe(null, e -> Assert.assertTrue(e.getSuppressed()[0].getMessage().contains ("\t|_\tFlux.publish"))); t.filter(d -> true).subscribe(null, e -> Assert.assertTrue(e.getSuppressed()[0].getMessage().contains ("\t\t|_\tFlux.publish"))); t.distinct().subscribe(null, e -> Assert.assertTrue(e.getSuppressed()[0].getMessage().contains ("\t\t\t|_\tFlux.publish"))); t.connect(); } finally { Hooks.resetOnOperatorDebug(); } }
@Override public int getPrefetch() { return source.getPrefetch(); }
@Override public void subscribe(CoreSubscriber<? super O> actual) { CoreSubscriber<? super I> input = lifter.apply(source, actual); Objects.requireNonNull(input, "Lifted subscriber MUST NOT be null"); source.subscribe(input); } }
@Override protected List<Scenario<String, String>> scenarios_operatorSuccess() { return Arrays.asList( scenario(f -> f.replay().autoConnect()), scenario(f -> f.replay().refCount()) ); }
@Override public void connect(Consumer<? super Disposable> cancelSupport) { this.source.connect(); }
@Test public void testMultiReceiver() throws Exception { Hooks.onOperatorDebug(); try { ConnectableFlux<?> t = Flux.empty() .then(Mono.defer(() -> { throw new RuntimeException(); })).flux().publish(); t.map(d -> d).subscribe(null, e -> assertThat(e.getSuppressed()[0]).hasMessageContaining("\t|_\tFlux.publish")); t.filter(d -> true).subscribe(null, e -> assertThat(e.getSuppressed()[0]).hasMessageContaining("\t\t|_\tFlux.publish")); t.distinct().subscribe(null, e -> assertThat(e.getSuppressed()[0]).hasMessageContaining("\t\t\t|_\tFlux.publish")); t.connect(); } finally { Hooks.resetOnOperatorDebug(); } }
@Override public int getPrefetch() { return source.getPrefetch(); }
@Override public void subscribe(CoreSubscriber<? super O> actual) { CoreSubscriber<? super I> input = lifter.apply(source, actual); Objects.requireNonNull(input, "Lifted subscriber MUST NOT be null"); if (actual instanceof QueueSubscription && !(input instanceof QueueSubscription)) { //user didn't produce a QueueSubscription, original was one input = new FluxHide.SuppressFuseableSubscriber<>(input); } //otherwise QS is not required or user already made a compatible conversion source.subscribe(input); } }
/** * Connects this {@link ConnectableFlux} to the upstream source when the specified amount of * {@link org.reactivestreams.Subscriber} subscribes. * <p> * Subscribing and immediately unsubscribing still contributes to the counter that * triggers the connection. * * <p> * <img class="marble" src="doc-files/marbles/autoConnectWithMinSubscribers.svg" alt=""> * * @param minSubscribers the minimum number of subscribers * * @return a {@link Flux} that connects to the upstream source when the given amount of Subscribers subscribed */ public final Flux<T> autoConnect(int minSubscribers) { return autoConnect(minSubscribers, NOOP_DISCONNECT); }
/** * Connects to the upstream source when the given number of {@link org.reactivestreams.Subscriber} subscribes. * Disconnection can happen in two scenarios: when the upstream source completes (or errors) then * there is an immediate disconnection. However, when all subscribers have cancelled, * a <strong>deferred</strong> disconnection is scheduled. If any new subscriber comes * in during the {@code gracePeriod} that follows, the disconnection is cancelled. * * <p> * <img class="marble" src="doc-files/marbles/refCountWithMinSubscribersAndGracePeriod.svg" alt=""> * * @param minSubscribers the number of subscribers expected to subscribe before connection * @param gracePeriod the {@link Duration} for which to wait for new subscribers before actually * disconnecting when all subscribers have cancelled. * * @return a reference counting {@link Flux} with a grace period for disconnection */ public final Flux<T> refCount(int minSubscribers, Duration gracePeriod) { return refCount(minSubscribers, gracePeriod, Schedulers.parallel()); }
@Override public void connect(Consumer<? super Disposable> cancelSupport) { source.connect(cancelSupport); }
@Override public int getPrefetch() { return source.getPrefetch(); }