Idiomatic way to update lock expiry time for ACT_RU_JOB

I have long running process wrapped in the async ServiceTask (2 hours+) as I’m trying to use Flowable as batch process orchestrator.
The problem is I don’t want to change flowable.process.async.executor.async-job-lock-time default value (actually I want to have it lower, i.e. 10 minutes) because it affects for how long the process will be stuck if executor goes down abruptly - I don’t want worker to wait 2 hours doing nothing because of the lock.

Is there an idiomatic way to update ACT_RU_JOB lock_expiry_time from ServiceTask code?
I want to update the lock time i.e. each 1 minute, so that I can use small value of async-job-lock-time by simply updating lock lease time myself.
Or even, maybe as a feature - it would be great if flowable updated that lock_time itself if ServiceTask thread is still alive

1 Like

If the logic is so-long running, a service task is probably not the right approach (keeping a db transaction open that long isn’t a good idea). A better approach might be using an external worker task: BPMN 2.0 Constructs · Flowable Open Source Documentation (which doesn’t keep anything on Flowable’s side open untildone).

@joram Thanks for reply, but same problem is present for ExternalWorkerJob - no way to update lock lease time in java interfaces

We hade the same problem, async-job-lock-time indicates time when another engine could take task to execution in case of another(locking) engine dies/restarts. But what if this task simple takes longer…

We solved this by starting thread with following code, too manualy increase exp_time

Thread thread = new Thread(() -> {
			while (true) {
				try {
					Thread.sleep(cfg.getAsyncExecutor().getAsyncJobLockTimeInMillis() / 2);
					try (Connection connection = dataSource.getConnection()) {
						try (PreparedStatement prepareStatement = connection.prepareStatement(
								"update act_ru_job set lock_exp_time_=? where lock_owner_=? and lock_exp_time_ is not null and create_time_ > lock_exp_time_ - interval '5' hour")) {
							LocalDateTime moveTime =, ChronoUnit.MILLIS);
							prepareStatement.setTimestamp(1, Timestamp.valueOf(moveTime));
							prepareStatement.setString(2, cfg.getAsyncExecutor().getLockOwner());
				} catch (Exception e) {
					LOGGER.error(e.getMessage(), e);

@MirekSz thanks. I use similar solution via Springs’ scheduler

@Scheduled(fixedDelayString = "\${flowable-executor.heartbeat.extend-schedule:PT1M}")
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    fun extendLockLease() {
        val leaseTime = config.asyncExecutor.asyncJobLockTimeInMillis
        for (execId in activeExecutionsForHeartbeat) {
   { "Extending lease for $execId" }
            try {
                val jobs = manager.createJobQuery().executionId(execId).locked().list()
                jobs.forEach {
                    val query = em.createNativeQuery("UPDATE act_ru_job SET lock_exp_time_ = ?2 WHERE id_= ?1 AND lock_exp_time_ IS NOT NULL")
                    val gregorianCalendar = GregorianCalendar()
                    gregorianCalendar.time = config.clock.currentTime
                    gregorianCalendar.add(Calendar.MILLISECOND, leaseTime)
                    query.setParameter(2, gregorianCalendar.time, TemporalType.TIMESTAMP)
       { "Extended lease for $execId for ${leaseTime}ms" }
            } catch (ex: Throwable) {
                logger.error(ex) { "Failed updating lease for $execId" }

But the point is (@joram ) there is no native way to update lock time… Locking for fixed amount of time is not ideal solution, update based on liveness would be better, at least for ExternalWorkerJob, as external workers can easily fail and locking something for long is bad idea