camunda / camunda-bpm-platform

Flexible framework for workflow and decision automation with BPMN and DMN. Integration with Quarkus, Spring, Spring Boot, CDI.
https://camunda.com/
Apache License 2.0
4.08k stars 1.54k forks source link

I can define an asynchronous continuation directly after a called process completes #2583

Open ThorbenLindhauer opened 3 years ago

ThorbenLindhauer commented 3 years ago

This issue was imported from JIRA:

Field Value
JIRA Link CAM-13829
Reporter aBggK1a
What is this name? This pseudonym name was generated based on the user name in JIRA to protect the personal data of our JIRA users. You can use this identifier to search for issues by the same reporter.
Has restricted visibility comments true

User Story (Required on creation):

Setup:

I want to use call activities that call BPMN processes from one application domain to another. Currently, I cannot define an asynchronous continuation boundary exactly between the execution boundary of the two processes when the called process finishes (see Hints section for details).

Functional Requirements (Required before implementation):

Technical Requirements (Required before implementation):

Limitations of Scope (Optional):

Hints (Optional):

When a called process finishes and returns to the calling process, the following steps happen:

  1. Execution of end listeners of the called process
  2. Completion of the called process instance (e.g. history)
  3. Control flow returns into the calling process instance
  4. Execution of the delegate variable mapping
  5. Execution of end execution listeners of the call activity
  6. Remaining execution of the called process until transaction boundaries are reached

asyncAfter on the call activity creates an asynchronous continuation after step 5.

It should be possible to define an asynchronous continuation between either step 2 and 3, or 3 and 4.


Original description

Acceptance Criteria (Required on creation):

In this project there are three process engine working in a deployment-aware mode:

  1. core-workflow
  2. core-processes
  3. domain-hello-world

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

In WrapperProcess.bpmn, the call activity "Start domain process" has an end listener org.example.DomainProcessStartFinishTaskListener. Both WrapperProcess.bpmn and DomainProcessStartFinishTaskListener are located inside core-processes engine.

Because DomainProcessStartFinishTaskListener is defined in core-processes engine and referenced only in WrapperProcess.bpmn, I want this listener to be executed inside core-processes engine.

Instead, it is being executed inside the domain-hello-world engine.

Here are the steps to reproduce:

  1. Start the process "Starter Process" via the tasklist. You should see the output "DomainProcessStartFinishTaskListener.notify" in the console of core-processes – that's the start listener working.
  2. Go to the tasklist and complete the human task.

Expected behavior: Another "DomainProcessStartFinishTaskListener.notify" in the core-processes console.

Actual behavior:

Inside domain-hello-world engine, an incident is created:

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

{{}}

Full stack trace is available here:

https://gist.github.com/dptij/144bc619c3c1c2262a1f1d7605384666

At the bottom of it you can 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

{{}}

The incorrect behavior is that Camunda tries to execute DomainProcessStartFinishTaskListener in domain-hello-world engine (and not core-processes engine).

Hints (Optional):

  1. Setting "async-before" and "async-after" to true in all activities did not help.

Links:

ThorbenLindhauer commented 3 years ago

This comment was imported from JIRA and written by user aBggK1a

What is this name? This pseudonym name was generated based on the user name in JIRA to protect the personal data of our JIRA users. You can use this identifier to search for issues by the same reporter.


Attached the archive with the code and the file with the stack trace.

ThorbenLindhauer commented 3 years ago

This comment was imported from JIRA and written by user @koevskinikola


Hi aBggK1a,

Thanks for submitting this bug report, and for the detailed information you provided. I will try to reproduce it next week, and provide you with feedback as soon as I have it.

Best, Nikola

ThorbenLindhauer commented 3 years ago

This comment was imported from JIRA and written by user @ThorbenLindhauer


Hi aBggK1a,

I have transformed this ticket into a feature request since the process engine currently does not have the functionality you are describing. Due to the engine's transaction and threading model \<1>, it always executes processes synchronously until it reaches wait states (e.g. user tasks or asynchronous continuations). This happens for example when a Java Delegate starts another process (regardless of any deployment-aware configurations), and the same in this case with call activities: When the call activity completes, the calling process continues to the next wait state.

The earliest possible wait state is if you declare async after on the call activity, however as you have noticed this does not prevent that certain delegation code like an end execution listener is executed before that point is reached. As a new feature, we could define a new type of asynchronous continuation point that comes earlier in the execution phase. I have updated the ticket description accordingly.

One way to deal with this situation as of today is to move the end execution listener to the sequence flow that leaves the call activity, as that will be executed after the async after point.

We will keep the ticket in our backlog, however won't pursue it as of now due to other commitments with higher priorities.

Cheers, Thorben

\<1> https://docs.camunda.org/manual/7.15/user-guide/process-engine/transactions-in-processes/