我如何告诉Camel我将结束自己处理的邮件

时间:2018-02-18 18:51:59

标签: apache-camel

我正在编写一个接收Camel Exchange的组件(端点),如下所示:

from("file|activemq|whatever").to(myEndpoint);

收到后,我希望它将交换传递给一组子程序,这些子程序可以异步工作,最终决定它们已经完成,可能在Exchange的Out消息中组成一个响应。所有这些都可能发生在Camel Context之外,我只使用Exchange对象。

然后我的子例程应该调用一些东西来告诉Camel它应该传回响应,根据源和中间组件要求做其他事情(例如,如果它是file:/,重命名文件)并考虑本交易所完成的路由。

我在想我会调用Exchange的工作done方法。

不幸的是,我注意到Camel仍然试图在错误的时间和状态下自行结束交换。例如,对于文件源,它无法重命名已经删除的文件。

以下是我的一些代码:

这里我定义了一个端点:

        _proceeder = new DefaultEndpoint() {

            private final String _defaultUri = "rex:producer-" + UUID.randomUUID().toString();

            @Override
            protected String createEndpointUri() {
                return _defaultUri;
            }

            @Override
            public Producer createProducer() throws Exception {

                return new DefaultAsyncProducer(this) {

                    @Override
                    public boolean process(final Exchange exchange1, final AsyncCallback callback) {

                        final ExchangeWrapper exchange = new ExchangeWrapper(_uri, exchange1, MessageSystem.this);
                        _LOG.debug("Got input for {}. Processing...", _uri);

                        exchange._taken(); // 1. all subsequent will increase by 1

                        /// some majick....

                        final boolean done = exchange._released(); // if all were released immediately, itll be 0 and sent back now. otherwise the last to release will send it back.

                        if (done) {
                            _LOG.debug("Processed input for {} synchronously", _uri);

                            //callback.done(true);
                        } else {
                            _LOG.debug("Processed input for {} asynchronously, awaiting response", _uri);

                            //exchange1.addOnCompletion(new Synchronization() {
                            //    @Override
                            //    public void onComplete(Exchange exchange) {
                            //        onFailure(exchange);
                            //    }
                            //

                            //    @Override
                            //    public void onFailure(Exchange exchange) {
                            //        callback.done(false);
                            //    }
                            //});

                        }

                        return done;
                    }
                };

            }

            @Override
            public Consumer createConsumer(Processor processor) throws Exception {
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
            }

            @Override
            public boolean isSingleton() {
                return true;
            }
        };

        _proceeder.setCamelContext(context);

毋庸置疑,我不明白为什么在我的DefaultAsyncProducer.process()方法中给出了AsyncCallback;无论我调用它的done()方法,系统都不会看到这个并且仍然会再次结束交换。但这不是问题。

这是ExchangeWrapper _released_done方法:

    private void _done() throws Exception {
        UnitOfWork uow = _exchange.getUnitOfWork();
        uow.done(_exchange);
        //try{
        //    uow.stop();
        //}catch(Exception e){
        //    
        //}
        _exchange.setUnitOfWork(null);
    }

    private boolean _released() {
        final boolean ret;
        final int cnt;
        final int trancnt;
        synchronized (_exchange) {
            cnt = _exchange.getProperty("rex.takenCount", Integer.class) - 1;
            _exchange.setProperty("rex.takenCount", cnt);
            trancnt = _exchange.getProperty("rex.takenAsTransient", Integer.class);
        }

        if (_LOG.isDebugEnabled()) {
            _LOG.debug("Input for {} released. {} times left, {} transient", new Object[]{_exchange.getProperty("rex.uri", String.class), cnt, trancnt});
        }
        if (cnt <= 0 || cnt <= trancnt) {

            if (_LOG.isDebugEnabled()) {
                _LOG.debug("Message for {} is processed by all non-transient receivers. Setting done...", new Object[]{_exchange.getProperty("rex.uri", String.class)});
            }
            _done();
            ret = true;
            if (_LOG.isDebugEnabled()) {
                _LOG.debug("Message for {} is set done", new Object[]{_exchange.getProperty("rex.uri", String.class)});
            }

        } else {
            ret = false;
        }
        return ret;
    }

所以基本上我将Exchange包装起来以保持状态并决定何时停止处理。

在深入了解Camel内部结构时,我看到了一些类似的计数器,可以跟踪Exchange处理的次数,但是我想控制它,因此我自己的包装器。

那么我该怎么称呼而不是

        _exchange.getUnitOfWork().done(_exchange);

告诉Camel内部处理器和其他人没有必要标记交换,因为我这样做了吗?

我的最新发现是打电话给uow.stop();,以便它清除所有'后'处理器等,但我突然明白我可能会尝试自己攻击骆驼很长一段时间,但最好还是问一下那些人没有尝试和猜测就知道该做什么。

这些是我的路线的例子:

        RouteBuilder rb = new RouteBuilder(_context) {
            @Override
            public void configure() throws Exception {
                if (_tokenizer != null) {
                    from(_uri).split().method(_tokenizer, "tokenizeReader").streaming().to(_proceeder);
                } else {
                    from(_uri).to(_proceeder);
                }
            }
        };

如果我可以避免构建路由,实例化端点和生产者,以及使用独立处理器,我很乐意这样做,但我不想抛弃奇妙的Camel项目在拆分,流式传输,编组方面所提供的功能。等等;所有这些似乎都建立在路线上。

1 个答案:

答案 0 :(得分:0)

可能我不清楚你想用这个做什么,但让我试试。

  

收到后,我希望它将交换传递给一组   子程序,可以异步工作,最终会工作   决定他们已经完成了

所以为此你可以编写一个processor并在路径的末尾配置它。在你的处理器中你可以使用一个线程池,向它提交子程序任务,等待它们完成并决定你是否想要改变消息体(正确解释here的方法,用一个很好的图表解释通过路由的交换流),并且camel将自动负责根据交换返回路由调用者的响应{{3 }}。例如,在您的情况下,如果路由从文件/ activemq路由开始,则它是基于事件/单向交换,并且不会向呼叫者发送响应,因为没有呼叫者客户端。这只是一个启动交流的活动。

更新 要使用camel中的异步处理功能来增强可伸缩性,请查看pattern示例,其中包含强烈推荐的this本书中的代码