在RxJava中取消超时任务

时间:2015-04-18 10:21:04

标签: java future rx-java completable-future

我正在尝试使用RxJava和Java 8的CompletableFuture类 并且不太了解如何处理超时条件。

import static net.javacrumbs.futureconverter.java8rx.FutureConverter.toObservable;

// ...

    Observable<String> doSomethingSlowly() {
        CompletableFuture<PaymentResult> task = CompletableFuture.supplyAsync(() -> {
            // this call may be very slow - if it takes too long, 
            // we want to time out and cancel it.
            return processor.slowExternalCall();

        });

        return toObservable(task);
    }

    // ...

    doSomethingSlowly()
        .single()
        .timeout(3, TimeUnit.SECONDS, Observable.just("timeout"));

这基本上有效(如果达到超时三秒,&#34;超时&#34;已发布)。然而,我还想取消我在Observable中包含的未来任务 - 是否可能采用以RxJava为中心的方法?

我知道一个选项是使用task.get(3, TimeUnit.SECONDS)来处理超时,但我想知道是否可以在RxJava中执行所有任务处理。

1 个答案:

答案 0 :(得分:10)

是的,你可以这样做。您可以向Subscription添加Subscriber

这允许您收听取消订阅,如果您明确调用subscribe().unsubscribe()Observable成功完成或出错,则会发生取消订阅。

如果您在未来完成之前看到取消订阅,则可以假定它是明确的unsubscribe或超时。

public class FutureTest {
    public static void main(String[] args) throws IOException {
        doSomethingSlowly()
                .timeout(1, TimeUnit.SECONDS, Observable.just("timeout"))
                .subscribe(System.out::println);
        System.in.read(); // keep process alive
    }

    private static Observable<String> doSomethingSlowly() {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
            }
            return "Something";

        });
        return toObservable(future);
    }

    private static <T> Observable<T> toObservable(CompletableFuture<T> future) {
        return Observable.create(subscriber -> {
            subscriber.add(new Subscription() {
                private boolean unsubscribed = false;
                @Override
                public void unsubscribe() {
                    if (!future.isDone()){
                        future.cancel(true);
                    }
                    unsubscribed = true;
                }

                @Override
                public boolean isUnsubscribed() {
                    return unsubscribed;
                }
            });

            future.thenAccept(value -> {
                if (!subscriber.isUnsubscribed()){
                    subscriber.onNext(value);
                    subscriber.onCompleted();
                }
            }).exceptionally(throwable -> {
                if (!subscriber.isUnsubscribed()) {
                    subscriber.onError(throwable);
                }
                return null;
            });
        });
    }
}