Таймер Ejb вызывает исключение javax.ejb.ConcurrentAccessTimeoutException: не удается получить блокировку записи

#java #jakarta-ee #timer #ejb #ejb-3.1

#java #джакарта-ee #таймер #ejb #ejb-3.1

Вопрос:

мое приложение работает на tomee, и у меня есть таймер ejb для запуска метода тайм-аута каждые две минуты. Таймер запустил метод тайм-аута в первый раз и все еще работает, когда таймер попытался запустить тот же метод во второй раз. И он выдал следующее исключение..

 javax.ejb.ConcurrentAccessTimeoutException: Unable to get write lock on 'timeout' method for: com.abc.xyz
        at org.apache.openejb.core.singleton.SingletonContainer.aquireLock(SingletonContainer.java:298)
        at org.apache.openejb.core.singleton.SingletonContainer._invoke(SingletonContainer.java:217)
        at org.apache.openejb.core.singleton.SingletonContainer.invoke(SingletonContainer.java:197)
        at org.apache.openejb.core.timer.EjbTimerServiceImpl.ejbTimeout(EjbTimerServiceImpl.java:769)
        at org.apache.openejb.core.timer.EjbTimeoutJob.execute(EjbTimeoutJob.java:39)
        at org.quartz.core.JobRunShell.run(JobRunShell.java:207)
        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:560)
 

Весь мой журнал заполнен одним и тем же стеком, и это продолжается до тех пор, пока я не остановлю сервер..

Можем ли мы заставить службу времени не запускать метод, если он уже запущен? или есть способ отложить первый вызов до его повторного запуска..

Спасибо,

Ответ №1:

Является ли ваш синхронизированный EJB одноэлементным компонентом? По умолчанию одиночные модули используют управляемый контейнером параллелизм с блокировками записи, которые гарантируют эксклюзивный доступ для всех методов.

openejb.xml настраивает время доступа для одноэлементного EJB. После этого тайм-аута будет выдано исключение, которое вы видели. Пожалуйста, смотрите также здесь: http://tomee.apache.org/singleton-beans.html

Решения могут быть:

  1. Используйте компонент сеанса без состояния в качестве компонента таймера
  2. Определите блокировку чтения для метода таймера
  3. Не используйте повторяющийся таймер, а запланируйте следующее выполнение вашего таймера в конце текущего выполнения.

Ответ №2:

Если вы хотите избежать параллельного запуска несколько раз, но также хотите избежать того, чтобы запланированные запуски стояли в очереди, тогда у меня есть другое предложение.

Таким образом, я позволяю расписаниям «пропустить», если предыдущее все еще выполняется:

 @Singleton
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class Example
{
    private final AtomicBoolean alreadyRunning = new AtomicBoolean(false);

    @Schedule(minute = "*", hour="*", persistent = false)
    public void doWork()
    {
        if (alreadyRunning.getAndSet(true)) return;

        try
        {
            //  ... your code
        }
        finally
        {
            alreadyRunning.set(false);
        }
    }
}