我是一个简单的监听器模式实现(以简洁形式),如下所示:
public class EmailProducer implements Runnable {
private List<Consumer<EmailMessage>> listeners = new ArrayList<>();
private IdleManager idleManager;
public void registerListener(Consumer<EmailMessage> listener) {
listeners.add(listener);
}
public void run() {
Session session = Session.getDefaultInstance(new Properties());
idleManager = new IdleManager(session, Executors.newCachedThreadPool());
// use IMAP IDLE to listen for new incoming emails
Folder inbox = openInbox();
inbox.addMessageCountListener(new MessageCountAdapter() {
public void messagesAdded(MessageCountEvent ev) {
Message[] msgs = ev.getMessages();
for (Message msg : msgs) {
EmailMessage info = EmailMessage.from(msg);
for (Consumer<EmailMessage> listener : listeners) {
listener.accept(info);
}
}
}
});
try {
idleManager.watch(inbox);
catch (FolderClosedException|StoreClosedException ex) {
run(); // restart, need to re-establish connection
}
}
}
因此,从本质上讲,它会从我的收件箱中抓取电子邮件,从每封电子邮件中提取信息并将其转换为内部邮件格式。
典型的Consumer
会保留该消息,另一个会在HTML页面上显示信息,而另一个可能会触发第三方系统执行某些操作。所有这一切都很好。
现在,我正试图在Consumer
失败时获得更多弹性。例如,如果持久性消费者失败(抛出异常),结束处理,我希望我的EmailMessage
继续存在。在这种情况下,我希望在暂停间隔后重试处理。现在,如果消费者失败,消息就会丢失。
我最近发现了Reactor,我认为它的编排会保存消息并使我能够做我需要的事情。但是,我没有看到如何将我当前的Runnable
调整到它的模型中。从documentation开始,我似乎需要一个RingBufferProcessor
来保存我的消息。我无法找到另一种方法,然后将处理器传递到我的Runnable
,因为它调用onNext()
方法而不是单独的侦听器accept
方法。我错过了什么,或者这是它应该工作的方式吗?
(额外的Cookie用于向我展示我在消费者失败时如何重试)
答案 0 :(得分:1)
您可以查看RingBufferProcessor
,它可以让您使用单个EmailMessage
执行并行任务。您可以将其设置为:
ReactorProcessor<Message, Message> processor = RingBufferProcessor.share("email-processor", 1024);
Stream<Message> s = Streams.wrap(processor);
s.consume(m -> firstTask(m));
s.consume(m -> secondTask(m));
s.consume(m -> thirdTask(m));
这会将工作并行化为3个独立的线程(每个Consumer
1个)。要进行重试或捕获错误,您需要Stream.retry
或Stream.retryWhen
(用于退避)或仅Stream.when
(它不会向您提供导致误差)。
s.retry(t -> t instanceof IllegalStateException)
.consume(m -> retryMessage(m));
s.when(NumberFormatException.class, e -> e.printStackTrace());
然后要向此Processor
发布消息,只需致电onNext
:
for(EmailMessage msg : msgs) {
processor.onNext(msg);
}