0
votes

We use Camunda BPM with Spring Boot and MS SqlServer and we would like to implement generic service task which decides at runtime if it runs sync or async (based on metadata of service being invoked). It would allow us to model specific process easily without "hardcoding" information if service works in sync/async way.

It works pretty well using following code:

class CustomServiceTask : AbstractBpmnActivityBehavior() {

    @Throws(Exception::class)
    override fun execute(execution: ActivityExecution) {

        val isSync: Boolean = ... // get service info
        if (isSync) {

            // do your stuff in sync mode  
            // invoke service, for example via REST 

            leave(execution)

        } else {

            // do your async stuff here - do something like:
            //  - submit jms/kafka/... message
            //  - start another process
            //  - ... 

            // TODO: enforce persisting process to db here?
        }

    }

    @Throws(Exception::class)
    override fun signal(execution: ActivityExecution, signalName: String?, signalData: Any?) {

        logger.info("${execution.activity.id}: Received signal for execution [${execution.id}] now, leaving execution now.")
        // leave the service task activity:
        leave(execution)
    }

    companion object {
        private val logger = LoggerFactory.getLogger(CustomServiceTask::class.java)!!
    }

}

Anyway there is one more problem - sometimes it happens, that the async service is too fast and it signals the process yet before it's state is persisted to camunda database - if I understand that correctly, it is fixed by marking the service task asyncBefore/asyncAfter, which forces the transaction to be committed after executing the service task code. (Correct?)

Is there any way to achieve the same from the code of service task itself?

I was trying something like

Context.getCommandContext().transactionContext.commit()

but not sure if it is correct.

1
Why do you need that? What is the use case? Have you thought about external tasks?Zelldon
The goal is to use same service task impl for both sync and async tasks and make model independent on fact if service works sync or async; actually, we would like to change it during runtime and still use the same process. External Tasks - although I like the concept, we would like to avoid it due to overhead with polling etc.miran

1 Answers

1
votes

I think you misunderstood the usage and meaning of the asyncBefore and asyncAfter flag.

These flags indicates that the engine should go async before or after the task. They mark a transaction boundary. For example reaching a task with an asyncAfter means, after executing the task the transaction will be commited and a new job is created to continue the workflow processing async. For more information please see the Transactions in processes documentation.

It does not mean, that your task implementation is async. It is way more complicated to achieve this. You could take a look in this blogpost. But be aware that this solution uses internal API.

As an alternative you could use the external task pattern as I mentioned in the comments or simply send and receive tasks.