flowable/flowable-engine · error

exception during timer job move for engine {}. Exception mes

Error message

exception during timer job move for engine {}. Exception message: {}

What it means

WARN log from the timer-job move step: a non-optimistic-lock Throwable was thrown while moving acquired timer jobs from the timer table to the executable job table. Because the jobs were already acquired (locked), the runnable unlocks them (unlockTimerJobs) before returning so they are not stranded.

Source

Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/asyncexecutor/AcquireTimerJobsRunnable.java:236

        lifecycleListener.stopAcquiring(getEngineName());

        return millisToWait;
    }

    protected void executeMoveTimerJobsToExecutableJobs(List<TimerJobEntity> timerJobs) {
        try {
            if (configuration.isGlobalAcquireLockEnabled()) {
                commandExecutor.execute(new BulkMoveTimerJobsToExecutableJobsCmd(jobManager, timerJobs));
            } else {
                commandExecutor.execute(new MoveTimerJobsToExecutableJobsCmd(jobManager, timerJobs));
            }

        } catch (FlowableOptimisticLockingException optimisticLockingException) {
            logOptimisticLockingException(optimisticLockingException);
            unlockTimerJobs(timerJobs); // jobs have been acquired before, so need to unlock when exception happens here

        } catch (Throwable t) {
            LOGGER.warn("exception during timer job move for engine {}. Exception message: {}", getEngineName(), t.getMessage(), t);
            unlockTimerJobs(timerJobs); // jobs have been acquired before, so need to unlock when exception happens here

        }
    }

    protected void logOptimisticLockingException(FlowableOptimisticLockingException optimisticLockingException) {
        if (configuration.isGlobalAcquireLockEnabled()) {
            LOGGER.warn("Optimistic locking exception (using global acquire lock) for engine {}", getEngineName(), optimisticLockingException);

        } else {
            LOGGER.debug(
                "Optimistic locking exception during async job acquisition. If you have multiple async executors running against the same database, " +
                    "this exception means that this thread tried to acquire a due async job, which already was acquired by another " +
                    "async executor acquisition thread.This is expected behavior in a clustered environment. " +
                    "You can ignore this message if you indeed have multiple async executor acquisition threads running against the same database. " +
                    "For engine {}. Exception message: {}",
                getEngineName(), optimisticLockingException.getMessage());

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Read the chained stack trace for the underlying DB/command error
  2. Verify the affected jobs were unlocked (the code calls unlockTimerJobs); if stranded locked jobs remain, reset their lock owner/time manually
  3. Check ACT_RU_TIMER_JOB and ACT_RU_JOB for rows violating constraints (e.g. duplicate IDs)
  4. Retry the cycle; jobs that were unlocked will be re-acquired

Example fix

// manually unstick stranded locked timer jobs
UPDATE ACT_RU_TIMER_JOB SET LOCK_OWNER_ = NULL, LOCK_EXP_TIME_ = NULL WHERE LOCK_OWNER_ = 'dead-node';
Defensive patterns

Strategy: retry

Validate before calling

// detect stranded locked timer jobs periodically
SELECT LOCK_OWNER_, COUNT(*) FROM ACT_RU_TIMER_JOB WHERE LOCK_EXP_TIME_ < NOW() GROUP BY LOCK_OWNER_;

Try / catch

try {
    moveTimerJobs();
} catch (Throwable t) {
    unlockTimerJobs(timerJobs); // always release acquired locks before retry
}

Prevention

When it happens

Trigger: Exception during executeMoveTimerJobsToExecutableJobs: failure in MoveTimerJobsCmd / bulk move operation, DB errors while writing to ACT_RU_JOB, or version conflicts other than optimistic locking.

Common situations: DB constraint violations during the move; connection failure between acquire and move; duplicated timer job rows after a failed earlier migration.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/5cab29ae5665fb32. Report an issue: GitHub.