-
Type: Bug
-
Status: Open
-
Priority: Minor
-
Resolution: Unresolved
-
Affects Version/s: None
-
Fix Version/s: QualifiedToSchedule
-
Component/s: Events / Works
-
Tags:
In some cases, we want to not schedule a work if it is already scheduled or running.
Typically when asking for the same lazy rendition computation twice in a row on an unchanged document, the first call should schedule a rendition work, the second one shouldn't.
The current code in AbstractLazyCachableRenditionProvider tries to avoid this by doing:
String workId = work.getId(); WorkManager wm = Framework.getService(WorkManager.class); if (wm.find(workId, null) == null) { wm.schedule(work, Scheduling.IF_NOT_SCHEDULED); }
See https://github.com/nuxeo/nuxeo/commit/e67cf15d06257a90df1bd78aaaa2ed5761cae9db and NXP-20716 for details.
Yet, there are at least 2 issues:
1/ We cannot rely on the work state
Introspect works to deduce a state or a result isn't good:
- There can be some race conditions.
- It's not a work's function to keep a state or a result.
- This is not supported on Stream WorkManager
So we shouldn't be using WorkManager#find(String workId, State state)
that relies on WorkQueuing#find(String workId, State state), thus on:
- Work#getWorkInstanceState() in memory
- RedisWorkQueuing#isWorkInState(String workId, State state) with Redis
2/ The current WorkManager API bypasses the scheduling parameter
Indeed, in WorkManagerImpl#schedule(Work work, Scheduling scheduling, boolean afterCommit), the work is scheduled in any case when using IF_NOT_SCHEDULED or IF_NOT_RUNNING_OR_SCHEDULED:
case IF_NOT_SCHEDULED: case IF_NOT_RUNNING_OR_SCHEDULED: // TODO disabled for now because hasWorkInState uses isScheduled // which is buggy boolean disabled = Boolean.TRUE.booleanValue(); if (!disabled && hasWorkInState(workId, scheduling.state)) { if (log.isDebugEnabled()) { log.debug("Canceling schedule because found: " + scheduling); } return; } break; } queuing.workSchedule(queueId, work);
Possible solution
Use the Key/Value store to save the scheduled and running jobs with a temporary value, "processing" for instance, and let the job remove the key when it's completed.
We should use a short TTL.
Let's try to write a standard pattern for the lazy renditions so that it serves as a global example.
- depends on
-
NXP-23379 Prevent multiple execution of work with same id in Stream WorkManager
- Resolved