Skip to content

Commit

Permalink
fix(engine): use correct classloader with priority job acquisition
Browse files Browse the repository at this point in the history
* On WildFly 12+, whem `jobExecutorAcquireByPriority` is set to true,
  the wrong classloader is used, and job acquisition fails. This commit
fixes this issue by explicitly switching to the ProcessEngine
classloader.

Related to CAM-9913
  • Loading branch information
koevskinikola committed May 21, 2021
1 parent 2449c9c commit 5753cd2
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,7 @@ protected void unlockJob(String nextJobId, CommandExecutor commandExecutor) {
* @return the classloader before the switch to return it back after the job execution
*/
protected ClassLoader switchClassLoader() {
ClassLoader classLoaderBeforeExecution = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(ProcessEngine.class.getClassLoader());
return classLoaderBeforeExecution;
return ClassLoaderUtil.switchToProcessEngineClassloader();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@
import java.util.Iterator;
import java.util.List;

import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.impl.ProcessEngineImpl;
import org.camunda.bpm.engine.impl.ProcessEngineLogger;
import org.camunda.bpm.engine.impl.interceptor.CommandExecutor;
import org.camunda.bpm.engine.impl.util.ClassLoaderUtil;


/**
Expand Down Expand Up @@ -65,6 +67,8 @@ public synchronized void run() {

Iterator<ProcessEngineImpl> engineIterator = jobExecutor.engineIterator();

// See https://jira.camunda.com/browse/CAM-9913
ClassLoader classLoaderBeforeExecution = ClassLoaderUtil.switchToProcessEngineClassloader();
try {
while (engineIterator.hasNext()) {
ProcessEngineImpl currentProcessEngine = engineIterator.next();
Expand All @@ -80,6 +84,8 @@ public synchronized void run() {
LOG.exceptionDuringJobAcquisition(e);

acquisitionContext.setAcquisitionException(e);
} finally {
ClassLoaderUtil.setContextClassloader(classLoaderBeforeExecution);
}

acquisitionContext.setJobAdded(isJobAdded);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

import javax.servlet.ServletContextEvent;

import org.camunda.bpm.engine.ProcessEngine;

/**
* @author Daniel Meyer
*
Expand Down Expand Up @@ -76,4 +78,16 @@ public ClassLoader run() {
}
}

/**
* Switch the current Thread ClassLoader to the ProcessEngine's
* to assure the loading of the engine classes during job execution.
*
* @return the current Thread ClassLoader
*/
public static ClassLoader switchToProcessEngineClassloader() {
ClassLoader currentClassloader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(ProcessEngine.class.getClassLoader());
return currentClassloader;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. Camunda licenses this file to you under the Apache License,
* Version 2.0; you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.camunda.bpm.integrationtest.functional.classloading.jobexecution;

import static org.junit.Assert.assertTrue;

import java.io.ByteArrayOutputStream;
import java.util.List;

import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.camunda.bpm.engine.impl.jobexecutor.JobExecutor;
import org.camunda.bpm.engine.runtime.Job;
import org.camunda.bpm.integrationtest.util.AbstractFoxPlatformIntegrationTest;
import org.camunda.bpm.model.bpmn.Bpmn;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.OperateOnDeployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.asset.Asset;
import org.jboss.shrinkwrap.api.asset.ByteArrayAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Test;
import org.junit.runner.RunWith;

/*
See https://jira.camunda.com/browse/CAM-9913
*/
@RunWith(Arquillian.class)
public class ClassloadingByJobPriorityTest extends AbstractFoxPlatformIntegrationTest {

protected static final BpmnModelInstance process = Bpmn.createExecutableProcess("asyncTaskProcess")
.startEvent()
.serviceTask()
.camundaExpression("${true}")
.camundaAsyncBefore()
.endEvent()
.done();

@Deployment(name= "engineWithPriorityJobAcquisition")
public static WebArchive processArchive() {
return initWebArchiveDeployment("processApp.war",
"org/camunda/bpm/integrationtest/functional/classloading/jobexecution/engineWithAcquireJobsByPriority.xml")
.addAsResource(modelAsAsset(process), "ClassloadingByJobPriorityTest.testDeployProcessArchive.bpmn");

}

@Test
@OperateOnDeployment("engineWithPriorityJobAcquisition")
public void testDeployProcessArchive() {
// given
ProcessEngineConfigurationImpl configuration = (ProcessEngineConfigurationImpl) processEngineService
.getProcessEngine("engineWithJobPriority")
.getProcessEngineConfiguration();
configuration.getRuntimeService().startProcessInstanceByKey("asyncTaskProcess");

// when
JobExecutor jobExecutor = configuration.getJobExecutor();
waitForJobExecutorToProcessAllJobs(jobExecutor, 12000);

// then
List<Job> availableJobs = configuration.getManagementService().createJobQuery().noRetriesLeft().list();
assertTrue(availableJobs.isEmpty());
}

protected static Asset modelAsAsset(BpmnModelInstance modelInstance) {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
Bpmn.writeModelToStream(byteStream, modelInstance);

byte[] bytes = byteStream.toByteArray();
return new ByteArrayAsset(bytes);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<process-application
xmlns="http://www.camunda.org/schema/1.0/ProcessApplication"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.camunda.org/schema/1.0/ProcessApplication http://www.camunda.org/schema/1.0/ProcessApplication ">

<process-engine name="engineWithJobPriority">
<job-acquisition>default</job-acquisition>
<configuration>org.camunda.bpm.engine.impl.cfg.StandaloneProcessEngineConfiguration</configuration>
<properties>
<property name="history">full</property>
<property name="historyCleanupEnabled">false</property>
<property name="jobExecutorAcquireByPriority">true</property>
<property name="databaseType">h2</property>
<property name="databaseSchemaUpdate">create-drop</property>
<property name="jdbcUrl">jdbc:h2:mem:engineWithJobPriority</property>
</properties>
</process-engine>

<process-archive>
<process-engine>engineWithJobPriority</process-engine>
<properties>
<property name="isDeleteUponUndeploy">true</property>
<property name="isScanForProcessDefinitions">true</property>
</properties>
</process-archive>

</process-application>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<process-application
xmlns="http://www.camunda.org/schema/1.0/ProcessApplication"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.camunda.org/schema/1.0/ProcessApplication http://www.camunda.org/schema/1.0/ProcessApplication ">

<process-engine name="engineWithJobPriority">
<job-acquisition>default</job-acquisition>
<datasource>java:jboss/datasources/ProcessEngine</datasource>
<properties>
<property name="history">full</property>
<property name="historyCleanupEnabled">false</property>
<property name="jobExecutorAcquireByPriority">true</property>
</properties>
</process-engine>

<process-archive>
<process-engine>engineWithJobPriority</process-engine>
<properties>
<property name="isDeleteUponUndeploy">true</property>
<property name="isScanForProcessDefinitions">true</property>
</properties>
</process-archive>

</process-application>

0 comments on commit 5753cd2

Please sign in to comment.