How to send cancel signal to ConnectableFlowable? - java

I use disposable Flowable to emit and subscribe items. But when I try to use ConnectableFlowable I can not send cancel signal to emitter. How can I understand flowable is disposed inside Flowable.create method?
You can see the scenario by comment and uncomment 'publish().autoConnect()' code snipped.
Disposable disposable = Flowable.create(emitter -> {
AtomicBoolean isRunning = new AtomicBoolean(true);
AtomicInteger i = new AtomicInteger();
new Thread(() -> {
while (isRunning.get()) {
i.getAndIncrement();
System.out.println("Emitting:" + i.get());
emitter.onNext(i.get());
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
emitter.setCancellable(() -> {
System.out.println("Cancelled");
isRunning.set(false);
});
}, BackpressureStrategy.BUFFER)
.publish() //comment here
.autoConnect() //and here
.subscribe(s -> {
System.out.println("Subscribed:" + s);
});
Thread.sleep(10_000);
disposable.dispose();
Thread.sleep(100_000);

There is an overload that gives you access to the Disposable to cancel the connection:
SerialDisposable sd = new SerialDisposable();
source.publish().autoConnect(1, sd::set);
// ...
sd.dispose();

Related

How to throw Timeout exception for the task inside parallel stream

The code I want to achieve is as below:
StreamSupport.stream(jsonArray.spliterator(), true).forEach(s ->{
try {
//invoke other api and set timeout for its execution
}
catch(TimeoutException e) {
s.getAsJsonObject().addProperty("processStatus", "Failure");
}
});
Can anyone help me in achieving "invoke other api and set timeout for it's execution" case in the above snippet?
I don't think you can do that inside a stream, but you can wrap the execution in a Callable like so to achieve the same result:
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new Task());
try {
System.out.println(future.get(1, TimeUnit.SECONDS));
}catch (Exception e) {
future.cancel(true);
e.printStackTrace();
} finally {
executor.shutdownNow();
}
}
private static class Task implements Callable<String> {
#Override
public String call(){
IntStream.of(1,2,3,4,5,6,7,8,9).parallel().forEach(t -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
return "ok";
}
}

How can I asynchronously emit to as Sink?

I have following proactive method.
void acceptSome(Consumer<? super String> consumer) {
consumer.accept("A");
consumer.accept("B");
}
And I wrote following method for reactor.
void emitAll(Sinks.Many<String> sink) {
try {
acceptSome(e -> {
sink.emitNext...(e);
});
sink.emitComplete...
} catch (Exception e) {
sink.emitError...
}
}
And I tested with following two methods, one with full buffer and the other with single buffer using thread.
#Test
void emitAll__onBackpressureBufferAll() {
final var sink = Sinks.many().unicast().<String>onBackpressureBuffer();
TheClass.emitAll(sink);
sink.asFlux()
.doOnNext(e -> {
log.debug("next: {}", e);
})
.blockLast();
}
#Test
void emitAll__onBackpressureBufferOne() {
var sink = Sinks.many().unicast().<String>onBackpressureBuffer(new ArrayBlockingQueue<>(1));
new Thread(() -> {
sink.asFlux()
.doOnNext(e -> {
log.debug("next: {}", e);
})
.blockLast();
}).start();
TheClass.emitAll(sink);
}
Now, How can I (Can I do that?) implement a method accepts a sink and returns a Flux or CompletableFuture<Flux> so that caller simply subscribe to the result without thread, with minimum buffer?
CompletableFuture<Flux<String>> emitAllAsync(Sinks.Many<String> sink) {
}
Thank you.
I tried some and it works yet doesn't seem righteous.
void emitAll(Sinks.Many<String> sink, Semaphore semaphore) {
try {
acceptSome(v -> {
try {
semaphore.acquire();
} catch (final InterruptedException ie) {
Thread.currentThread().interrupt();
throw new RuntimeException(ie);
}
log.debug("emitting {}", v);
sink.tryEmitNext(v).orThrow();
});
sink.tryEmitComplete().orThrow();
} catch (final IOException ioe) {
log.error("failed to emit to {}", sink, ioe);
sink.tryEmitError(ioe).orThrow();
}
}
CompletableFuture<Flux<String>> emitAllAsync() {
var sink = Sinks.many().unicast().<String>onBackpressureBuffer(new ArrayBlockingQueue<>(1));
var semaphore = new Semaphore(1);
CompletableFuture
.runAsync(() -> emitAll(sink, semaphore));
return CompletableFuture.completedFuture(sink.asFlux().doOnNext(v -> semaphore.release()));
}

CompletableFuture.allOff completes even if one CompletableFuture in its list is not yet finished

I have 2 CompletableFutures. The task2 should only start once task1 finishes. Then, I need to wait for all tasks to finish. In my code below, the program ends after task1 ends. The task2 starts but did not finish. Any ideas why this happens? Also, why is it that the list only contains 1 entry while in the code, I added 2?
Code:
public void testFutures () throws Exception {
List<CompletableFuture<Void>> futures = new ArrayList<>();
CompletableFuture<Void> task1 = CompletableFuture.supplyAsync( () -> {
System.out.println(" task1 start");
try {
Thread.sleep(5000L);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println(" task1 done");
return null;
});
task1.whenComplete( (x, y) -> {
CompletableFuture<Void> task2 = CompletableFuture.supplyAsync( () -> {
System.out.println(" task2 start");
try {
Thread.sleep(2000L);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println(" task2 done");
return null;
});
futures.add(task2);
});
futures.add(task1);
// wait for the calls to finish
try {
CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).whenComplete( (x, y) -> {
System.out.println(" all tasks done " + futures.size());
}).get();
} catch (Exception e) {
e.printStackTrace();
}
}
Output:
task1 start
task1 done
all tasks done 1
task2 start
Let's first clean your code.
Let's define a method that will do the sleeping, so that it does not muddy the water:
private static void sleep(int seconds) {
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(seconds));
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
Then let's separate the tasks and use proper methods:
private static CompletableFuture<Void> task1() {
return CompletableFuture.runAsync(() -> {
System.out.println(" task1 start");
sleep(5);
System.out.println(" task1 done");
});
}
private static CompletableFuture<Void> task2() {
return CompletableFuture.runAsync(() -> {
System.out.println(" task2 start");
sleep(2);
System.out.println(" task2 done");
});
}
You need to understand that chaining of CompletableFuture methods already do exactly what you want, they run the next stage, after the previous one has ended. You can make your code far, far more easy with:
public static void main(String[] args) throws Exception {
testFutures();
}
private static void testFutures() throws Exception {
CompletableFuture<Void> both = task1().thenCompose(ignoreMe -> task2());
both.get();
System.out.println("both done");
}
You have two problems.
First, you've created a race condition as to when task2 gets added to your list of futures. At the time you execute this line—
CompletableFuture.allOf(...).get();
—which I'll call the terminating getter, you only have task1 in the list. See for yourself by outputting its size:
// wait for the calls to finish
try {
System.out.println("# of futures: " + futures.size()); // 1
task2 still runs eventually, because you scheduled it with whenComplete(). But it's not your terminating getter that triggers it.
Recall that I said it's a race condition. To demonstrate this for yourself, add a sleep() before the terminating getter, like so:
try {
Thread.sleep(6000L);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
// wait for the calls to finish
try {
System.out.println("# of futures: " + futures.size()); // 2
Then you'll have given it enough time to add task2.
But here's the thing. Now is the terminating getter triggering both tasks?
Still no! And that's the second problem: You almost always want to use one of the thenRun(), thenAccept(), thenApply(), thenCompose() methods. These methods chain your futures, i.e. make each stage dependent on the previous, so that your terminating getter actually waits for the entire chain to complete. whenComplete() is a special method that kicks off a totally unrelated pipeline and is thus unaffected by the terminating get().
In your case, you want to use thenRun(), like this:
task1.thenRun( ignore -> {
Okay, so how do we combine all that?
public static void testFutures () throws Exception {
CompletableFuture<Void> task1 = CompletableFuture.supplyAsync( () -> {
System.out.println(" task1 start");
try {
Thread.sleep(5000L);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println(" task1 done");
return null;
});
CompletableFuture<Void> futuresChain = task1.thenRun( () -> {
System.out.println(" task2 start");
try {
Thread.sleep(2000L);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println(" task2 done");
});
// wait for the calls to finish
try {
futuresChain.thenRun( () -> {
System.out.println(" all tasks done ");
}).toCompletableFuture().get();
} catch (Exception e) {
e.printStackTrace();
}
}
Output:
task1 start
task1 done
task2 start
task2 done
all tasks done
You see, you only need to supplyAsync() for the first task. You want to run task2 sequentially after that task, so thenRun() will do the scheduling (the supplyAsync()ing) for you. So you don't need an array of futures either. The allOf() is for when you want to run tasks in parallel, and wait for all of them to finish.

Asynchronous forEach over an array with RxJava

I am trying to iterate over an array of Maps and do some asynchronous actions. I have tried a few things using the RxJava library, but everything I've tried seems to be synchronous. I am trying to avoid creating new threads manually and want to let RxJava handle it. This is what I've tried so far.
Observable.from(new Map[20])
.subscribeOn(Schedulers.newThread())
.observeOn(Schedulers.computation())
.forEach(batch -> {
try {
System.out.println(1);
Thread.sleep(3000);
System.out.println(2);
} catch (Exception e) {
}
});
Observable.from(new Map[20])
.subscribeOn(Schedulers.newThread())
.observeOn(Schedulers.computation())
.subscribe(batch -> {
try {
System.out.println(1);
Thread.sleep(3000);
System.out.println(2);
} catch (Exception e) {
}
});
Observable.from(new Map[20])
.subscribeOn(Schedulers.newThread())
.subscribe(batch -> {
try {
System.out.println(1);
Thread.sleep(3000);
System.out.println(2);
} catch (Exception e) {
}
});
Observable.from(new Map[20])
.subscribe(batch -> {
try {
System.out.println(1);
Thread.sleep(3000);
System.out.println(2);
} catch (Exception e) {
}
});
When I run unit tests with the code above I see the following output.
1
2
1
2
1
2
...
What I want to see is
1
1
1
...
2
2
2
How do I iterate asynchronously over a Map array using RxJava?
You can achieve it changing from Observable to Flowable and use parallel:
Flowable.fromIterable(array)
.parallel(3) // number of items in parallel
.runOn(Schedulers.newThread()) // the desired scheduler
.map(item -> {
try {
System.out.println(1);
Thread.sleep(3000);
System.out.println(2);
} catch (Exception e) {
}
return Completable.complete();
})
.sequential().subscribe();
If you're stuck using RxJava 1.x then you wont have access to the Flowable class. This wasn't my case, but something like the below code can do parallel actions. There is more nesting, but it works.
final ExecutorService executor = Executors.newFixedThreadPool(2);
List<String> iterableList = new ArrayList<>();
iterableList.add("one");
iterableList.add("two");
iterableList.add("three");
iterableList.add("4");
iterableList.add("5");
iterableList.add("6");
iterableList.add("7");
iterableList.add("8");
iterableList.add("9");
Observable.from(iterableList)
.flatMap(val -> Observable.just(val)
.subscribeOn(Schedulers.from(executor))
.doOnNext(numString -> {
try {
System.out.println(1);
Thread.sleep(500);
System.out.println(2);
} catch (Exception ex) {
}
})
)
.subscribe();

Hot(ish) Observable

I need to have something in between hot and cold Observable. It should emit items when client subscribes and stops emission when client unsubscribes. But when client subscribes to the same Observable the remained items should be delivered. And the last thing is time in between items.
Observable<String> hotishObservable = createHotishObservable("a", "b", "c");
Disposable sub = hotishObservable.subscribe();
// emit "a"
// 1 second passed
// emit "b"
sub.dispose()
Disposable sub = hotishObservable.subscribe();
// emit "c"
The obvious solution is to extend ObservableOnSubscribe and handle ObservableEmitter:
class HotishSub implements ObservableOnSubscribe<String> {
public HotishSub(String... items) {
this.items = items;
}
#Override
public void subscribe(ObservableEmitter<String> emitter) {
if(isNotEmpty())
emitter.onNext(nextItem);
executor.schedule(this::handleNext, 1000, TimeUnit.MILLISECONDS);
else
emitter.onComplete();
}
private void handleNext(){
//if emitter is not disposed and there're still items then emit it
}
}
Observable<String> createHotishObservable(String... items){
return Observable.create(new HotishSub(items));
}
Is there any better option?
It's needed for stream of messages from simplified chat bot. UI client code uses the same Observable to get stream of messages from bots and real users.
I use Flowable.generate to do it.
public static <T> Flowable<T> create(T... ts) {
List<T> list = new ArrayList<>(Arrays.asList(ts));
return Flowable.generate(() -> list, (l, e) -> {
if (l.isEmpty()) {
e.onComplete();
} else {
e.onNext(l.remove(0));
if (!l.isEmpty()) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
// you can use other way to delay it
}
}
}
});
}
Then test it
public static void main(String[] args) throws Exception {
Flowable<String> ob = create("a", "b", "c", "d", "e");
Disposable d = ob.subscribeOn(Schedulers.computation())
.subscribe(i -> System.out.println(System.currentTimeMillis() + "\t" + i));
Thread.sleep(2500);
d.dispose();
ob.subscribeOn(Schedulers.computation())
.blockingSubscribe(i -> System.err.println(System.currentTimeMillis() + "\t" + i));
}
And output:
1520304164412 a // sys.out
1520304165413 b // sys.out
1520304166413 c // sys.out
1520304166928 d // sys.err
1520304167927 e // sys.err

Categories

Resources