I am getting WriteLockManager.acquireLocksForClone() waits after upgrading to version 6_6.2025.10 (or later) when using submitting transactional workloads to a managed task executor.
From the release notes I can see that there is a change in the EclipseLink version : 4.0.7
-
When I run the same logic without the managed task executor everything is fine, even with high concurrency from the HTTP threads (REST calls).
-
Without high concurrency it runs fine, even when using the managed task executor.
-
As soon as I hit start submitting tasks in quick succession (from REST) and I am using the managed task executor. The system start locking up.
-
This is the kind of stack trace we get:
“http-thread-pool::http-listener-1(4)” #115 [71171] daemon prio=5 os_prio=31 cpu=28,57ms elapsed=552,00s allocated=2324K defined_classes=34 tid=0x000000012082a800 nid=71171 in O
bject.wait() [0x0000000315c10000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait0(java.base@21.0.9/Native Method)
- waiting on
at java.lang.Object.wait(java.base@21.0.9/Object.java:366)
at org.eclipse.persistence.internal.helper.WriteLockManager.acquireLocksForClone(WriteLockManager.java:185) - locked <0x0000000797afa9d0> (a org.eclipse.persistence.internal.identitymaps.HardCacheWeakIdentityMap$ReferenceCacheKey)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.cloneAndRegisterObject(UnitOfWorkImpl.java:1068)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.cloneAndRegisterObject(UnitOfWorkImpl.java:1026)
…
- A bit more testing shows that this is mostly likely due do a write in the managed task which does not get cleaned up properly in the L2 cache concurrency manager.
- See below same code for task submission and sample code of the task
Sample code of task submission:
...
@Resource
private ManagedExecutorService managedService;
@Resource
private ContextService contextService;
@Inject
private Instance<EmailWithTemplateTask> taskProvider;
...
EmailWithTemplateTask task = taskProvider.get();
task.setOrganisationId(orgId);
task.setTo(to);
// more task init code here
managedService.submit(contextService.createContextualProxy(task, Runnable.class));
...
EmailWithTemplateTask sample code:
@Dependent
public class EmailWithTemplateTask implements Runnable, ManagedTask {
@EJB
private OrganisationBean organisationBean;
...
@Override
public void run() {
try {
...
int orgId = 1;
Organisation org = organisationBean.get(orgId);
if (org == null) {
log.error("Not running managed task with jobId [" + jobId + "]. Failed to find org [" + orgId + "] in the system.");
return;
}
OrganisationManagedTask omt = new OrganisationManagedTask();
omt.setOrganisationId(org);
// more init code
omt = organisationBean.create(omt);
...
```
And the OrganisationBean sample code:
public OrganisationManagedTask create(OrganisationManagedTask omt) throws BeanValidationException {
// Validate
BeanValidationUtils.validate(omt);
// Get fresh org
Organisation o = em.find(Organisation.class, omt.getOrganisationId().getId());
// Wire both sides
omt.setOrganisationId(o);
o.getOrganisationManagedTaskList().add(omt);
em.persist(omt);
em.flush();
log.debug("Created new organisation managed task with id [" + omt.getId() + "]");
return omt;
}
This code has has been working fine for over 10 years. I think there might be an issue with write cache keys (Organisation: 1) not being released properly from tasks run from a managed executor under load.
Nothing else in the stack trace show threads stuck in the task code. So the write keys (Organisation: 1) should in theory always get released at the end the task execution.
Has anyone got any ideas?
Regards
Rainer