Search code examples
hibernatejakarta-eejpaproducer-consumer

How to write a producer-consumer using JPA


Currently I have a JPA entity for a kind of tasks. Some processes write to that table, and a scheduled process works on that tasks, and changes the state when ready. I need to prioritize tasks, and to retry them with decreasing frequency if they fail. My environment is GlassFish 3 + JPA via Hibernate + MySQL + XA transactions. In the medium term the project will replace GlassFish by a Spring solution (using Jetty or so).

It got this working somehow, but I'm not really happy with it: I get OptimisticLockExceptions, it looks like I didn't got the transactions right at some points, and JPA timers on GlassFish are also kind of messy if you need variable times.

I have the feeling I'm using the wrong tools here, and that I should use some mature, stable design, not something clubbed together. Using JPA entities seems to be to heavy-weight, but raw JDBC looks like an even worse choice. Of course I want to avoid heavy library dependencies, but maybe I overlook a simple "canned" solution for my specific problem (which doesn't seem so unusual).

[Edit]

In order to clarify: I won't change the use case (I don't even have the code anymore), I just want to get some general guidelines in order to "do it right" (TM) the next time. To answer the question from ben75: The worker might be multi-threaded, and I needed small transactions, as this should run all the time - maybe for months.


Solution

  • I think you just need to try to see the things from above in order to identify the roles in the process & detect the dependencies between the creator of the tasks, the processor(s) of the task and the priority-controller. After that, design for every of these roles clean reusable EJBs/Services.

    Sometimes, for relative short tasks that take just 10-20 seconds it makes more sense to force the user to wait, using Asynchronous EJBs (search for @Asynchronous), instead of creating a task.

    About the OptimisticLockExpcetions: these can occur because the data changes in the meanwhile, which can be caused by one of your other threads of the task-consumer, or by the client, which changes the data. Identify the cause and if that is the first case, correct the bug. Of course you would get more help you if you provide some code or explanations on how everything works.

    When processing the tasks: I would fetch the Task entities with Pessimistic Lock, so that another thread does not begin to process the same task.

    So I suppose your process is complex and your need a better/more flexible design.