Search code examples
javajmsmessage-queuespring-jmsweblogic11g

Queueing tasks via JMS


I would like to make a question to the comunity and get as many feedbacks as possible about an strategy I have been thinking, oriented to resolve some issues of performance in my project.

The context:

We have an important process that perform 4 steps.

  1. An entity status change and its persistence
  2. If 1 ends OK. Entity is exported into a CSV file.
  3. If 2 ends OK. Entity is exported into another CSV. This one with way more Info.
  4. If 3 ends OK. The last CSV is sent by mail

Steps 1 and 2 are linked and they are critical.

Steps 3 and 4 are not critical. Doesn't even care if they ends successfully.

Performance of 1-2 is fine, but 3-4 in some escenarios are just insanely slow. Mostly cause step 3.

If we execute all the steps as a sequence, some times step 3 causes a timeout. Client do not get any response about steps 1 and 2 (the important ones) and user don't know whats going on.

This case made me think in JMS queues in order to delegate the last 2 steps to another app/process. Deallocate the notification from the business logic. Second export and mailing will be processed when posible and probably in parallel. I could also split it in 2 queues: exports, mail notification.

Our webapp runs into a WebLogic 11 cluster, so I could use its implementation.

What do you think about the strategy? Is WebLogic JMS implementation anything good? Should I check another implementation? ActiveMQ, RabbitMQ,...

I have also thinking on tiketing system implementation with spring-tasks.

At this point I have to point at spring-batch. Its usage is limited. We have already so many jobs focused on important processes of data consolidation and the window of time for allocation of more jobs is limited. Plus the impact of to try to process all items massively at once.

May be we could if we find out a way to use the multithread of spring-batch but we didn't find yet the way to fit oír requirements into such strategy.

Thank you in advance and excuse my english. I promise to keep working hard on it :-).


Solution

  • One problem to consider is data integrity. If step n fails, does step n-1 need to be reversed? Is there any ordering dependencies that you need to be aware of? And are you writing to the same or different CSV? If the same, then might have contention issues.

    Now, back to the original problem. I would consider Java executors, using 4 fixed-sized pools and move the task through the pools as successes occur:

    1. Submit step 1 to pool 1, getting a Future back, which will be used to check for completion.
    2. When step 1 completes, you submit step 2 to pool 2.
    3. When step 2 completes, you now can return a result to the caller. The call to this point has been waiting (likely with a timeout so it doesn't hang around forever) but now the critical tasks are done.
    4. After returning to the client, submit step 3 to pool 3.
    5. When step 3 completes, submit step to pool 4.

    The pools themselves, while fixed sized, could be larger for pool 1/2 to get maximum throughput (and to get back to your client as quickly as possible) and pool 3/4 could be smaller but still large enough to get the work done.

    You could do something similar with JMS, but the issues are similar: you need to have multiple listeners or multiple threads per listener so that you can process at an appropriate speed. You could do steps 1/2 synchronously without a pool, but then you don't get some of the thread management that executors give you. You still need to "schedule" steps 3/4 by putting them on the JMS queue and still have listeners to process them.

    The ability to recover from server going down is key here, but Executors/ExecutorService has not persistence, so then I'd definitely be looking at JMS (and then I'd be queuing absolutely everything up, even the first 2 steps) but depending on your use case it might be overkill.