0

I am working on a mechanism in Camel that will choose an endpoint for a message from a flag that can be true or false. It's a throttling mechanism that will re-route messages to a bulk ingest endpoint (sent to HDFS) in the case that my upstream channel gets flooded.

Ultimately, my route looks like this:

from("queue:myqueue").bean("messageParser")
    .dynamicRoute(bean(ThrottleHelper.class, 'buildEndpoint'));

from('direct:regular').to('hbase');

from('direct:throttle').to('hdfs');

My ThrottleHelper class's buildEndpoint method looks like this:

public static String buildEndpoint() {
   synchronized(shouldThrottle) {
      if(shouldThrottle)
         return "direct:throttle";
      else
         return "direct:regular"
    }
} 

Currently, I have a method on the class called checkStatus(); which sets shouldThrottle (a static variable). checkStatus() is run on a Camel quartz timer every minute.

I've noticed some weird behavior and I think I may be misusing this pattern. From further searches on Camel's implementation of the pattern, it looks like buildEndpoint() will be called after each endpoint returned has been traversed by the message. Is this true? Or can I expect that the path will terminate after either going to "direct:throttle" or "direct:regular"?

From what I'm gathering on the web, should my method really look like this?

public static String buildEndpoint(Message message) {
   if(message.getHeader('throttled') != null)
      return null;
   else
      message.setHeader('throttled', true);

   synchronized(shouldThrottle) {
      if(shouldThrottle)
         return "direct:throttle";
      else
         return "direct:regular"
    }
} 

Thanks!

  • Nevermind. I verified this behavior with a unit test. The second method that I listed (which tests to see if the method has been called) works. My next question- Why would I use dynamicRouter instead of just having my ThrottleHelper enrich each message's header with the "shouldThrottle" property and use content-based routing based on that header property? – Corey J. Nolet Mar 27 '14 at 02:28

2 Answers2

0

From the official documentation it would seem, yes, your second construct is closer to the correct usage. Basically, the dynamic router can be used to route a message through multiple endpoints, not just a single endpoint that immediately terminates. To tell the dynamic router to stop routing your message to another endpoint, your bean must return null, as you have written in your final code snippet, to indicate that routing of this message is done.

ProgrammerDan
  • 871
  • 7
  • 17
  • The idea here was trying to get away from having to store extra properties on my messages. It was also to get away from having to iterate through filters/choices to figure out which endpoint the messages should traverse. It does seem, however, that it's almost more trouble than it's worth, especially if I still need to store state on the messages. I'm better off using the choice() construct here. – Corey J. Nolet Mar 27 '14 at 02:41
  • Fair enough, but I think your content-based routing idea is actually the best approach for this case. Enriching your message with an addition property is a pretty lightweight option, and it's basically designed the help facilitate your exact use-case. Might as well make use of the tools at hand that are a better match for your needs. – ProgrammerDan Mar 27 '14 at 02:43
  • Agreed. Thanks for your response! – Corey J. Nolet Mar 27 '14 at 02:58
0

As ProgrammerDan pointed out, the dynamic router is used to route a message through multiple endpoints, hence the need to explicitly return null to indicate the end of routing.

If all you want to do is choose a single endpoint using an expression or a bean method, you're better off using the dynamic recipient list instead (cfr. http://camel.apache.org/recipient-list.html). If you use .recipientList()instead of .dynamicRoute() in the route builder, your first buildEndpoint method implementation will work just fine.

gertv
  • 276
  • 1
  • 2