Closing the RuntimeManager
akoskm Aug 12, 2014 5:27 AMHello!
I'm unable to dispose my runtime manager when the process is finished. Here is how I'm creating my RuntimeManager:
public AppRuntime createSession(Long execId, List<Resource> resources, HashMap<String, Object> globals) throws ServiceException { KieBase kbase = createKieBase(execId, resources, null); RuntimeEnvironment environment = RuntimeEnvironmentBuilder.getDefault() .persistence(false) .entityManagerFactory(emf) .userGroupCallback(this.getUsersAndGroups()) .knowledgeBase(kbase) .get(); DefaultRegisterableItemsFactory rif = (DefaultRegisterableItemsFactory) environment.getRegisterableItemsFactory(); RuntimeManager runtimeManager = RuntimeManagerFactory.Factory.get().newPerProcessInstanceRuntimeManager("runtime-" + execId); RuntimeEngine runtime = runtimeManager.getRuntimeEngine(ProcessInstanceIdContext.get()); KieSession session = runtime.getKieSession(); modifySession(session, null, globals); AppRuntime appRuntime = new AppRuntime(runtimeManager, runtime); return appRuntime; }
And here is how I'm destroying it:
public class BpmProcessListener implements ProcessEventListener { // .. other method implementations @Override public void afterProcessCompleted(ProcessCompletedEvent event) { if (DEBUG_LISTENER) { LOG.debug("afterProcessCompleted: " + event.toString()); } WorkflowProcessInstance pi = (WorkflowProcessInstance) event.getProcessInstance(); Long applicationId = (Long) event.getKieRuntime().getGlobal("__APPID"); Long execId = (Long) event.getKieRuntime().getGlobal("__EXECID"); String processId = (String) event.getKieRuntime().getGlobal("__MAIN_PROCESS_ID"); if (pi.getProcessId().equals(processId)) { if (applicationId != null) { bpmAppManager.removeFromSession(applicationId); // the method is called which initiates the dispose procedure, see below LOG.debug("Application {} was removed from session", applicationId); } else { LOG.warn("Application ID was null. Nothing to be removed from sessions map."); } this.broadcastStatus(execId); } } }
where the bpmAppManager.removeFromSession(applicationId) does the following:
/** * Holds [Application ID, AppSession] pairs. */ public final ConcurrentHashMap<Long, AppSession> sessions = new ConcurrentHashMap<>(); /** * Removes the session object associated with <i>applicationId</i> from the * session map. * * @param applicationId * @return true if the session object was found and was removed, false if no * associated session object was found in the session map */ public void removeFromSession(Long applicationId) { AppSession removed = sessions.remove(applicationId); removed.shutdownRuntime(); }
finally:
public class AppSession implements Serializable { private Long applicationId; private Long executionId; private Long processInstanceId; private AppRuntime appRuntime; // ... public void shutdownRuntime() { RuntimeManager runtimeManager = this.appRuntime.getRuntimeManager(); RuntimeEngine runtimeEngine = runtimeManager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId)); runtimeManager.disposeRuntimeEngine(runtimeEngine); runtimeManager.close(); } }
The AppRuntime is something similar to what you call DeployedUnit in kie. Since the user can start multiple processes, I'm holding the references to each created RuntimeManager.
My test processes mainly containing Human Tasks. During the interaction with the TaskService I discovered that sometimes taskService.complete tries to complete a process which is connected with a RuntimeManager instance which should be already destroyed, but for some reason ProcessInstanceIdContext is still seeing it. My guess was that I end up with broken links to already disposed RuntimeEngines.
To prove that I changed the code
RuntimeManager runtimeManager = RuntimeManagerFactory.Factory.get().newPerProcessInstanceRuntimeManager(environment, "exec-" + execId);
to
RuntimeManager runtimeManager = RuntimeManagerFactory.Factory.get().newPerProcessInstanceRuntimeManager(environment);
When happened is that after the first started and successfully completed process, when I started the second one I got the following exception:
! java.lang.IllegalStateException: RuntimeManager with id default-per-pinstance is already active
which shows that the previous RuntimeManager wasn't disposed even if I did it in shutdownRuntime().
Is there any other way to dispose the RuntimeEngine?