基于内容的限制

时间:2012-09-11 11:44:08

标签: apache-camel

我想知道Camel是否可以根据交换内容进行限制。

情况如下:我必须通过肥皂拨打网络服务。其中,发送到该Web服务的参数有一个customerId。问题是如果给定customerId每分钟有超过1个请求,则webservice会发回错误。

我想知道是否可以使用Camel为每个customerId实施限制。因此,不应对所有消息实施限制,而只应对具有相同customerId的消息实施限制。

让我知道如何实现这一点,或者我是否需要澄清我的问题。

3 个答案:

答案 0 :(得分:1)

ActiveMQ Message Groups旨在处理此案例。因此,如果您可以在路由中引入JMS队列跃点,那么只需将JMSXGroupId标头设置为customerId即可。然后在另一个路由中,您可以从此队列中使用并发送到您的Web服务以获取您描述的行为。

另见http://camel.apache.org/parallel-processing-and-ordering.html了解更多信息......

答案 1 :(得分:1)

虽然ActiveMQ消息组肯定会处理唯一客户ID的并行处理,但在我的评估中,克劳斯是正确的,为每个唯一的组引入一个限制代表Camel / ActiveMQ的未实现功能。

仅消息组不符合所描述的SLA。虽然每组消息(由客户ID相关)将按顺序处理,每个组有一个线程,但只要请求花费不到一分钟就能收到响应,就不会强制执行每个客户每分钟一个请求的要求。

那就是说,我很想知道是否可以以模拟JIRA中的功能请求的方式组合消息组和节流策略。到目前为止,我的尝试失败了。我正在思考这些问题:

<route>
  <from uri="activemq:pending?maxConcurrentConsumers=10"/>
  <throttle timePeriodMillis="60000">
    <constant>1</constant>
    <to uri="mock:endpoint"/>
  </throttle>
</route>

但是,节流似乎应用于移动到端点的整个请求集,而不是应用于每个单独的消费者。我不得不承认,我发现这种行为有点惊讶。我的期望是节流将单独应用于每个消费者,这将满足原始问题中的SLA,前提是消息包含JMSXGroupId头中的客户ID。

答案 2 :(得分:0)

我遇到了类似的问题,最后提出了这里描述的解决方案。

我的假设是:

  • 消息顺序并不重要(尽管可以通过重新定序器解决)
  • 每个客户ID的消息总量不是很大,因此运行时间不会饱和。

解决方案方法:

  • 使用customerID将聚合器运行1分钟,同时将具有相同客户ID的邮件汇总到列表中
  • 使用拆分器将列表拆分为单个消息
  • 将第一条消息从拆分器发送到实际服务
  • 将列表的其余部分重新路由回聚合器。

Java DSL版本更容易理解:

final AggregationStrategy aggregationStrategy = AggregationStrategies.flexible(Object.class)
        .accumulateInCollection(ArrayList.class);

from("direct:start")
    .log("Receiving ${body}")
    .aggregate(header("customerID"), aggregationStrategy).completionTimeout(60000)
        .log("Aggregate: releasing ${body}")
        .split(body())
        .choice()
            .when(header(Exchange.SPLIT_INDEX).isEqualTo(0))
                .log("*** Processing: ${body}")
                .to("mock:result")
            .otherwise()
              .to("seda:delay")
        .endChoice();

from("seda:delay")
    .delay(0)
    .to("direct:start");

Spring XML版本如下所示:

 <!-- this is our aggregation strategy defined as a spring bean -->
 <!-- see http://stackoverflow.com/questions/27404726/how-does-one-set-the-pick-expression-for-apache-camels-flexibleaggregationstr -->
 <bean id="_flexible0" class="org.apache.camel.util.toolbox.FlexibleAggregationStrategy"/>
 <bean id="_flexible2" factory-bean="_flexible0" factory-method="accumulateInCollection">
     <constructor-arg value="java.util.ArrayList" />
 </bean>

<camelContext xmlns="http://camel.apache.org/schema/spring">
       <route>
           <from uri="direct:start"/>
           <log message="Receiving ${body}"/>
           <aggregate strategyRef="_flexible2" completionTimeout="60000" >
               <correlationExpression>
                   <xpath>/order/@customerID</xpath>
               </correlationExpression>
               <log message="Aggregate: releasing ${body}"/>
               <split>
                   <simple>${body}</simple>
                   <choice>
                       <when>
                           <simple>${header.CamelSplitIndex} == 0</simple>
                           <log message="*** Processing: ${body}"/>
                           <to uri="mock:result"/>
                       </when>
                       <otherwise>
                           <log message="--- Delaying: ${body}"/>
                           <to uri="seda:delay" />
                       </otherwise>
                   </choice>
               </split>
           </aggregate>
       </route>

       <route>
           <from uri="seda:delay"/>
           <to uri="direct:start"/>
       </route>
</camelContext>