Search code examples
javabpmncamunda

Why does Camunda attempt to execute a task listener in the wrong process engine?


I have three Camunda engines using a shared database:

There is starter_wrapper_process.bpmn in core-workflow. This process starts WrapperProcess.bpmn defined in core-processes. Finally, WrapperProcess.bpmn starts DomainProcess.bpmn from domain-hello-world engine.

When

  1. WrapperProcess.bpmn starts DomainProcess.bpmn and
  2. DomainProcess.bpmn completes (i. e. execution returns to WrapperProcess.bpmn),

I want to execute a certain piece of code before a domain process starts and after it ends.

This piece of code must be located in core-processes and the developers of domain-hello-world must be able to create and run their processes without ever thinking about this piece of code.

Therefore the activity Start domain process has two task listeners (tab Listeners) which are supposed to execute DomainProcessStartFinishTaskListener before the domain process starts and after it finishes.

Image showing BPMN diagram in Camunda Modeler with the start and end task listener settings

Since this listener is referenced from and defined in core-processes I assume that it will run in core-processes (provided all engines run in deployment-aware mode).

But it doesn't.

Let's say I launch all three engines and start Starter Process via the task list. In the console output I see DomainProcessStartFinishTaskListener.notify which means that the start listener has been executed successfully.

Next, I go to the task list and complete the human task.

Now something unexpected happens: An incident occurs in the instance of DomainProcess.bpmn inside the domain-hello-world engine:

ENGINE-09008 Exception while instantiating class 'org.example.DomainProcessStartFinishTaskListener': ENGINE-09017 Cannot load class 'org.example.DomainProcessStartFinishTaskListener': org.example.DomainProcessStartFinishTaskListener

Incident in domain-hello-world engine

Full stack trace is available here.

At the bottom of it, you see a ClassNotFoundException:

Caused by: org.camunda.bpm.engine.ClassLoadingException: ENGINE-09017 Cannot load class 'org.example.DomainProcessStartFinishTaskListener': org.example.DomainProcessStartFinishTaskListener
    at org.camunda.bpm.engine.impl.util.EngineUtilLogger.classLoadingException(EngineUtilLogger.java:146)
    at org.camunda.bpm.engine.impl.util.ReflectUtil.loadClass(ReflectUtil.java:111)
    at org.camunda.bpm.engine.impl.util.ClassDelegateUtil.instantiateDelegate(ClassDelegateUtil.java:46)
    ... 187 more
Caused by: java.lang.ClassNotFoundException: org.example.DomainProcessStartFinishTaskListener

This is understandable -- org.example.DomainProcessStartFinishTaskListener is defined in core-processes (not in domain-hello-world).

What I cannot understand is why it is domain-hello-world that tries to execute the task listener which is referenced in BPMN file that is located in core-processes. DomainProcess does not contain any task listeners and does not refer to org.example.DomainProcessStartFinishTaskListener.

How do I need to modify my code in order for org.example.DomainProcessStartFinishTaskListener to always be executed in core-processes (both before the domain process starts and after it ends)?

Update 1: Setting async-after of the Start domain process as shown below activity did not help (commit.

Start domain process activity with async-after set to true

Update 2: I tried to set async-before and async-after in all activities of all processes (commit). I am still getting the same error.

Update 3: As a workaround, I moved the end listener to an event after the call activity.

Fragment of a new diagram


Solution

  • This error occurs if an execution originates and runs in wrong class loader (here the domain process). a) make sure you process engines are configured as deployment aware b) if this does not suffice, try changing the async before on the end event of the domain process to async after c) a workaround would be to set async after on the call activity and change the end listen on the call activity to a take listener on the subsequent sequence flow.