Code Monkey home page Code Monkey logo

camunda-platform-7-reactor's Introduction

Camunda Platform 7 Build project with Maven Maven Central

DEPRECATED: Note that this project is deprecated and archived

camunda-platform-7-reactor

for the previous version, please go to https://github.com/camunda/camunda-bpm-reactor/tree/1.2

Event-based listeners and delegates for Camunda BPM.

A note on this extension: the underlying reactor-eventbus was dropped when the reactor framework moved to pivotal afew years ago. This extension works on a fork (see extension/eventbus) of that bus, which unfortunately is not very well tested, it is supposed to work "as is" (and does).

Since the original extension authors meanwhile moved on to work with the camunda spring boot starter and use the spring event bridge to achieve the same effect as this extension does, it is not maintained on a regular basis.

TLDR: Use at own risk. It has proven to work in production environments. But if you are on spring-boot: do not use the reactor, use the spring-native event-bridge. And if you want this extension to prosper in the future: contact us and become a maintainer.

What is this about?

This extension provides a process engine plugin that registers Execution- and TaskListeners to all possible elements and all possible events. These listeners then publish their delegates (DelegateTask, DelegateExcution) to an event bus.

Custom implementations that are interested in certain events may register on that bus and will get notified and executed when the registered listeners fire.

Publishing and subscribing uses a topic pattern /camunda/{context}/{type}/{process}/{element}/{event} so it is possible to register on all that happens on the engine or the assignement event of a concrete userTask in a concrete process.

Reference: a similar approach was already done in the engine-cdi module using CDI observers and qualifiers.

Why do I need this?

Using an event bus decouples registration and implementation of listeners. The bpmn file has not to be touched for this. This is useful for implementations that can be considered "aspects" of the engine like task assignment and monitoring.

Instead of registering listeners all over your bpmn files that always call the same rule service to determine the candidate groups of a task or write runtime information to a data source, you just hook into the event bus stream and wait for notification.

While this could be achieved with custom plugins/parselisteners, these share the problem that the engine has to have access to the code of the listeners added. With the decoupling via eventbus, this is avoided.

How is it done?

This extension uses the event bus provided by projectreactor.io. This bus is fairly advanced and stable and allows separation of event-payload (the DelegateExpression) and event topic, so we do not need any additional qualifiers or concrete types to distinct between "listen to create of task B" or "listen to all events of task A".

Using the extension is straight forward, you need to:

  • access the eventBus instance used in the plugin by calling CamundaReactor.eventBus().
  • Use this bus to register an instance of an appropriate listener and specify the topic parts you are interested in.

Examples

Register a listener that is fired for all "create" events on any user task in the system.

@CamundaSelector(type = "userTask", event = TaskListener.EVENTNAME_CREATE)
public class TaskCreateListener implements TaskListener {
  
  public TaskCreateListener(EventBus eventBus) {
    eventBus.register(this);
  }

  @Override
  public void notify(DelegateTask delegateTask) {
   ...
  }
}

More examples can be found in the sub-module examples.

Configuration

If you have multiple task listener for an event, per default the task listener from this extension gets called in the end. When setting the following property to true, the reactor task listener get's always called first!

camunda.bpm.reactor.reactor-listener-first-on-user-task: true

Noteworthy

This extensions works with delegateTasks and delegateEvents directly. These cannot be used outside the current thread, so the eventBus used is synchronous.

Next Steps

  • provide extension for CDI (?)
  • use eventbus for message correlation end/start
  • ...

Maintainer

Contributors

Sponsors

Kühne+Nagel

License

camunda-platform-7-reactor's People

Contributors

akeller avatar berndruecker avatar boris-petrov avatar celanthe avatar chaima-mnsr avatar dependabot[bot] avatar gabrielcasaro avatar hawky-4s- avatar jangalinski avatar lwille avatar pschalk avatar saig0 avatar wgitscht avatar zambrovski avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

camunda-platform-7-reactor's Issues

java.lang.NullPointerException: null at org.camunda.bpm.extension.reactor.bus.SelectorBuilder.extractTypeName(SelectorBuilder.java:223)

Hello
I have a multi instance sub process and when i attach a boundary error catch event I get the following exception:

java.lang.NullPointerException: null
	at org.camunda.bpm.extension.reactor.bus.SelectorBuilder.extractTypeName(SelectorBuilder.java:223)

Exact code:

  static String extractTypeName(BpmnModelExecutionContext bpmnModelExecutionContext) {
    FlowElement bpmnModelElementInstance = bpmnModelExecutionContext.getBpmnModelElementInstance();
    return bpmnModelElementInstance.getElementType().getTypeName();
  }

This doesn't seem to be an issue if I attach a boundary timer event. According to the Camunda docs I should be able to attach a catch boundary error event on a multi instance sub process. Has anyone else noticed this issue?

Thanks

get processDefinitionKey from delegate without parsing the definitionId

We found out, that using a long processDefinitionKey, we can not rely on the processDefinitionId to have the form <KEY>:<REV>:<ID>. So registering listerners to events would fail, because we parse the processDefinitionId to get the key.

Though having an extra field on the delegate is prefered, as a workaround, we should use

delegate.getProcessEngineServices().getRepositoryService().getProcessDefinition(execution.getProcessDefinitionId).getKey()

Clean-up examples

  • enable ignored tests or remove it
  • update namespaces of bpmn
  • create index page for examples and link to it from start page
  • add docs for easier understanding
  • remove the spike from core module

Avoid wrong Event Registration

Currently, I can create a SubscriberExecutionListener and register it for a task event. This can lead to a ClassCastException when the listener is invoked.

Fix spring integration (spring/spring-starter)

Some projects that use this extension have problems with the autowiring of the reactor-plugin and the camunda-springboot-starter.

  • check if this is a general problem
  • fix it (or remove the spring extension again)

eventBus/listener failures do not raise exceptions, thus do not re-reroll transactions

The default behaviour of the reactor eventBus is non blocking so it catches exceptions rather than throwwing them.
In the special case of synchronous, in transaction listeners we do have in the camunda events, this is the wrong behavior.

  public static EventBus eventBus() {
          return new EventBusSpec().dispatchErrorHandler(Throwables::propagate)
                  .uncaughtErrorHandler(Throwables::propagate).get();
    }

Provide constants for activity types

while the event types can be accessed as String constants (TaskListener.CREATE), the activities (userTask, startEvent, ...) can't. It would make implementing selectors much easier if we had a constant class.

I would suggest that we start with those constants within this extension but aim to have those in camunda core soon.

remove SubscriberJavaDelegate

javaDelegates cannot be added by the ParseListener because they have to be set pre-parse, otherwise parsing would fail. So it makes no sense to ahve JavaDelegates triggered by events.

add bpmn/cmmn to topic (/camunda/bpmn/....)

It is important not to confuse cmmn/bpmn events, so we should add an explicit marker in the standard topic path.
To simplify usage, we should extend the CamundaSelector annotation so the user can choose between a BpmnSelector and a CmmnSelector that alreay holds the correct topic path

Failing test - InterruptingErrorEventTest

Hello,

Camunda extension jenkins job is failing because of the InterruptingErrorEventTest (recently added)

Delegate Expression 'serviceDelegate' did neither resolve to an implementation of 'interface org.camunda.bpm.engine.impl.pvm.delegate.ActivityBehavior' nor 'interface org.camunda.bpm.engine.delegate.JavaDelegate'.

I am attaching the log. If you have any questions please let me know.

failed_InterruptingErrorEventTest.txt

Release 1.0

I think we are good to go!

@saig0 can you please take over?

Release version: 1.0, next dev version: 1.1-SNAPSHOT.

Task listener gets executed before data is persisted in engine

Task listener is getting executed before the data is stored in database so there is a problem with using listeners for informing about flow of the process. For example:

If you are sending CREATE event via EventBus (from TaskListener) to some system and this system is then Calling API to get information about the User Task's form fields, the API will return that the task not exists. After some time (150ms) the task will be created but after the event is sent.

There is a possibility of specifying timeout after receiving event but we cannot be sure when will data actually be persisted and the call to API is safe to do.

resolve inter-test dependencies

Running in reversealphabetical order a test fails:

Failed tests:   fire_events_on_userTasks(org.camunda.bpm.extension.reactor.plugin.ReactorProcessEnginePluginTest):

need to check and fix

switch to reactor bus 3.0

once its available

This will also require Java8, so it will be an incompatible change (2.0) that will most certainly lead to very few maintanence on th 1.x branch.

remove static eventbus constant

turned out that using a static reference to a default eventBus causes more trouble (especially in testing, when the consumer registry piles up) than it was use, so I will get rid of it and initialize the plugin with a "new" bus everytime.

NPE in SelectorBuilder for CMMN tasks

Caused by: java.lang.NullPointerException
    at org.camunda.bpm.extension.reactor.SelectorBuilder.extractTypeName(SelectorBuilder.java:138) ~[camunda-bpm-reactor-core-1.0-SNAPSHOT.jar:1.0-SNAPSHOT]
    at org.camunda.bpm.extension.reactor.SelectorBuilder.selector(SelectorBuilder.java:26) ~[camunda-bpm-reactor-core-1.0-SNAPSHOT.jar:1.0-SNAPSHOT]
    at org.camunda.bpm.extension.reactor.listener.PublisherTaskListener.notify(PublisherTaskListener.java:20) ~[camunda-bpm-reactor-core-1.0-SNAPSHOT.jar:1.0-SNAPSHOT]

When using the SelectorBuilder with a DelegateTask, the builder is not aware of the CMMNness of the task and will therefore cast the DelegateTask to BpmnModelExecutionContext which - fo course - it is not.

introduce CamundaEventBus

So far, I tried to keep the API open by using the standard reactor.EventBus. But since this Bus must be synchronous and have a special error handling config for RuntimeExceptions and BpmnErrors, it is not wirth the efford.
You can still use a custom bus by extending the CamundaEventBus, but we wont pretend to be configuration agnostic.

In code this means that all usages of EventBus will become CamundaEventBus. Some subscription issues get easier that way too.

defer context "task" from tasklistener events

When registering st like:

      SelectorBuilder.selector()
            .event(TaskListener.EVENTNAME_CREATE)
            .context(Context.task)

the context info is today required but not needed. we can derive the context when using task events.

release 1.2

we really could use the spring extension as soon as possible, I think its worth a release. So once #36 is merged, it would be great if someone could take over.

Release version: 1.2
new dev versin: 1.3-SNAPSHOT

Shared-Environment integration

Hi Extension-Provider,

is it possible to deploy this Engine-Plugin in a shared environment on a tomcat?

Greetings
Eberhard Mayer

Class cast exception when using BPMN Transactions.

Hello,

When using reactor with a process with a BPMN Transaction I got this kind of error:

[main] [ERROR] context - ENGINE-16006 BPMN Stack Trace:
    Transaction_02x25sb (transition-notifiy-listener-start, ScopeExecution[7])
    Transaction_02x25sb
      ^
      |
    StartEvent_0hjbp2y

[main] [ERROR] context - ENGINE-16004 Exception while closing command context: ENGINE-03036 Cannot cast 'org.camunda.bpm.model.xml.impl.instance.ModelElementInstanceImpl@349df0df' to 'FlowElement'. Element is of type 'transaction' with namespace 'http://www.omg.org/spec/BPMN/20100524/MODEL'.
org.camunda.bpm.engine.ProcessEngineException: ENGINE-03036 Cannot cast 'org.camunda.bpm.model.xml.impl.instance.ModelElementInstanceImpl@349df0df' to 'FlowElement'. Element is of type 'transaction' with namespace 'http://www.omg.org/spec/BPMN/20100524/MODEL'.
    at org.camunda.bpm.engine.impl.db.EnginePersistenceLogger.castModelInstanceException(EnginePersistenceLogger.java:346)
    at org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity.getBpmnModelElementInstance(ExecutionEntity.java:1552)
    at org.camunda.bpm.extension.reactor.bus.SelectorBuilder.extractTypeName(SelectorBuilder.java:222)
    at org.camunda.bpm.extension.reactor.bus.SelectorBuilder.selector(SelectorBuilder.java:52)
    at org.camunda.bpm.extension.reactor.bus.CamundaEventBus.notify(CamundaEventBus.java:61)
    at org.camunda.bpm.extension.reactor.bus.CamundaEventBus$2.notify(CamundaEventBus.java:94)
    at org.camunda.bpm.extension.reactor.bus.CamundaEventBus$2.notify(CamundaEventBus.java:1)
    at org.camunda.bpm.engine.impl.core.instance.CoreExecution.invokeListener(CoreExecution.java:93)
    at org.camunda.bpm.engine.impl.core.operation.AbstractEventAtomicOperation.execute(AbstractEventAtomicOperation.java:51)
    at org.camunda.bpm.engine.impl.interceptor.AtomicOperationInvocation.execute(AtomicOperationInvocation.java:81)
    at org.camunda.bpm.engine.impl.interceptor.CommandContext.invokeNext(CommandContext.java:180)
    at org.camunda.bpm.engine.impl.interceptor.CommandContext.performNext(CommandContext.java:159)
    at org.camunda.bpm.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:134)
    at org.camunda.bpm.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:124)
    at org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:505)
    at org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity.performOperationSync(ExecutionEntity.java:480)
    at org.camunda.bpm.engine.impl.core.operation.AbstractEventAtomicOperation.execute(AbstractEventAtomicOperation.java:58)
    at org.camunda.bpm.engine.impl.interceptor.AtomicOperationInvocation.execute(AtomicOperationInvocation.java:81)
    at org.camunda.bpm.engine.impl.interceptor.CommandContext.invokeNext(CommandContext.java:180)
    at org.camunda.bpm.engine.impl.interceptor.CommandContext.performNext(CommandContext.java:159)
    at org.camunda.bpm.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:134)
    at org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:494)
    at org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:471)
    at org.camunda.bpm.engine.impl.pvm.runtime.operation.PvmAtomicOperationTransitionCreateScope.scopeCreated(PvmAtomicOperationTransitionCreateScope.java:34)
    at org.camunda.bpm.engine.impl.pvm.runtime.operation.PvmAtomicOperationCreateScope.execute(PvmAtomicOperationCreateScope.java:49)
    at org.camunda.bpm.engine.impl.pvm.runtime.operation.PvmAtomicOperationCreateScope.execute(PvmAtomicOperationCreateScope.java:23)
    at org.camunda.bpm.engine.impl.interceptor.AtomicOperationInvocation.execute(AtomicOperationInvocation.java:81)
    at org.camunda.bpm.engine.impl.interceptor.CommandContext.invokeNext(CommandContext.java:180)
    at org.camunda.bpm.engine.impl.interceptor.CommandContext.performNext(CommandContext.java:167)
    at org.camunda.bpm.engine.impl.interceptor.CommandContext.performOperation(CommandContext.java:134)
    at org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:494)
    at org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity.performOperation(ExecutionEntity.java:471)
    at org.camunda.bpm.engine.impl.pvm.runtime.PvmExecutionImpl.start(PvmExecutionImpl.java:229)
    at org.camunda.bpm.engine.impl.cmd.StartProcessInstanceCmd.execute(StartProcessInstanceCmd.java:75)
    at org.camunda.bpm.engine.impl.cmd.StartProcessInstanceCmd.execute(StartProcessInstanceCmd.java:35)
    at org.camunda.bpm.engine.impl.interceptor.CommandExecutorImpl.execute(CommandExecutorImpl.java:24)
    at org.camunda.bpm.engine.impl.interceptor.CommandContextInterceptor.execute(CommandContextInterceptor.java:95)
    at org.camunda.bpm.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:30)
    at org.camunda.bpm.engine.impl.RuntimeServiceImpl.startProcessInstanceByKey(RuntimeServiceImpl.java:66)
    at org.camunda.bpm.extension.reactor.process.BPMNTransactionProcessTest.start_bpmn_transaction_process(BPMNTransactionProcessTest.java:25)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:55)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: java.lang.ClassCastException: org.camunda.bpm.model.xml.impl.instance.ModelElementInstanceImpl cannot be cast to org.camunda.bpm.model.bpmn.instance.FlowElement
    at org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity.getBpmnModelElementInstance(ExecutionEntity.java:1548)
    ... 64 more

You have a faling test in the pull request #41

Wildfly ClassLoader issue

Hello,

Just trying to get this plugin working inside Wildfly, and to programatically add a listener from a web app. However i think i'm hitting an issue with Wildfly using different class loaders.

The instanceof check to find the plugin is failing despite the plugins variable containing the ReactorProcessEnginePlugin

Debugging and running some arbitrary code against it shows:

plugins.get(3).getClass()
	 (java.lang.Class<T>) class org.camunda.bpm.extension.reactor.plugin.ReactorProcessEnginePlugin

plugins.get(3).getClass().getClassLoader()
	 (org.jboss.modules.ModuleClassLoader) ModuleClassLoader for Module "org.camunda.bpm.extension.reactor.camunda-bpm-reactor-core:main" from local module loader @73d4cc9e (finder: local module finder @80169cf (roots: C:\projects\camunda-wildfly\server\wildfly-10.0.0.Final\modules,C:\projects\camunda-wildfly\server\wildfly-10.0.0.Final\modules\system\layers\base))
	 
Thread.currentThread().getClass().getClassLoader()
	 (org.jboss.modules.ModuleClassLoader) ModuleClassLoader for Module "org.jboss.msc:main" from local module loader @73d4cc9e (finder: local module finder @80169cf (roots: C:\projects\camunda-wildfly\server\wildfly-10.0.0.Final\modules,C:\projects\camunda-wildfly\server\wildfly-10.0.0.Final\modules\system\layers\base))

At the moment the Wildfly instance of starting the process engine at boot time, and my webapp is attempting to get hold of the ProcessEngine and the reactor to add a listener:

@PostDeploy
public void postDeploy(ProcessEngine processEngine) {
        CamundaEventBus eventBus = CamundaReactor.eventBus();
        eventBus.register(new ExecutionCompletionListener());
}

Any thought's on how to fix this?

Set up CI environment

we should have automatic builds at least of the master branch and publishing of the snapshot artifacts

switch to 7.4

although this will work with earlier versions, we should build against the current.

Tomcat fails to instantiate the plugin

I'm trying to use the ReactorProcessEnginePlugin when running Camunda in Tomcat (using the default Camunda 7.5.0 Tomcat distribution).

However, instantiation of the plugin fails due to not having a constructor that takes no parameters. See the error callstack in the attachment.

I believe a simple fix would be to add that missing version of the constructor and can provide a patch for that.

camunda-bpm-reactor-tomcat-callstack.txt

release 1.1

I think we are ready for a maintanence release.

New features: processEnginePlugin events, smaller fixes and examples.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.