Reactor中听众的主题是什么?

时间:2015-06-08 08:44:16

标签: java project-reactor

我是一个简单的监听器模式实现(以简洁形式),如下所示:

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用于向我展示我在消费者失败时如何重试)

1 个答案:

答案 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.retryStream.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);
}