我正在尝试制作一个反应式RabbitMQ侦听器,它允许我们处理具有多个订阅者的每条消息。当所有订阅者成功完成时,我们只希望ack
消息。
这是我目前的设置:
Observable
.fromCallable(() -> {
// Set up connection
return consumer;
})
.flatMap(consumer -> Observable
.fromCallable(consumer::nextDelivery)
.doOnError(throwable -> {
try {
consumer.getChannel().getConnection().close();
} catch (IOException ignored) { }
})
.repeat())
.retryWhen(observable -> observable.delay(3, TimeUnit.SECONDS))
.publish()
.refCount();
这将建立一次连接,与所有订阅者共享所有消息,并在3秒后重新连接,如果由于例如兔子变得无法使用。
我仍然需要做的是ack
或nack
消息。由于我们所有的消息处理程序都是幂等的,所以如果任何处理程序发生故障,我可以重新排队消息,以确保每个处理程序都能成功完成。
有没有办法判断任何订阅者是否失败?我目前正在考虑订阅这样的东西:
public void subscribe(Action1 action) {
deliveries
.flatMap(delivery -> Observable
.just(delivery)
.doOnNext(action)
.doOnError(throwable -> {
// nack
})
.doOnCompleted(() -> {
// ack
})
)
.subscribe();
}
但是在第一次失败或成功时,这显然是ack
或nack
。有没有办法merge
特定邮件的所有订阅者,然后检查错误或完成?
我还尝试过使用AtomicInteger
计算所有订阅者的数量,然后计算成功/失败次数,但很明显,只要有人在处理过程中订阅或取消订阅,就不会在不阻止整个处理步骤的情况下进行同步。 / p>
我也可以给每个订阅者Observable<Delivery>
并让他们返回错误或完成,类似于retryWhen
(作为一种回复频道),但我无法生成事先确定所需的可观察数量并将其合并。
有什么想法吗?谢谢你的阅读!
答案 0 :(得分:1)
您可以使用 onErrorResumeNext 来控制从管道传播的异常并设置 nack ,然后将您的onComplete用作 ack 强>
这是一个例子
Observable.just(null).map(Object::toString)
.doOnError(failure -> System.out.println("Error:" + failure.getCause()))
.retryWhen(errors -> errors.doOnNext(o -> count++)
.flatMap(t -> count > 3 ? Observable.error(t) : Observable.just(null).delay(100, TimeUnit.MILLISECONDS)),
Schedulers.newThread())
.onErrorResumeNext(t -> {
System.out.println("Error after all retries:" + t.getCause());
return Observable.just("I save the world!");
})
.subscribe(s -> System.out.println(s));
答案 1 :(得分:1)
您想使用Observable.mergeDelayError
,然后使用其中一种.onError*
方法。
第一个只在所有可观察者完成/出错之后传播错误;第二个将允许您在处理完成后处理错误。
编辑:要获得计数,请计算成功次数:
Object message = ...;
List<Action1<?>> actions = ...;
Observable.from(actions)
.map(action ->
Observable.defer(() -> Observable.just(action.call(message))
.ignoreEmements()
.cast(Integer.class)
.switchIfEmpty(1)
.onErrorReturnResumeNext(e->Observable.empty())
)
.compose(Observable::merge)
.count();
它有点复杂,可以更清楚:拨打电话,忽略错误,计算成功。