Camunda set Execution Variable - camunda

I'm trying to set a process variable in Task Listener of a human-task using Groovy script during 'create' as event type in Camunda BPMN work-flow.
execution.setVariable('newUserType',"RMAOFF1");
But it is giving me error saying "The task does not exist or the corresponding process instance could not be resumed successfully."
Any help most appreciated.

In a Task Listener you don't have an execution (DelegateExecution).
But you have a task (DelegateTask delegateTask).
So your example is: task.setVariable('newUserType',"RMAOFF1")
By the way this would also work in an expression ${task.setVariable('newUserType',"RMAOFF1")}
For more infos see https://docs.camunda.org/manual/7.18/user-guide/process-applications/process-application-event-listeners/

The signature of a TaskListener is void notify(DelegateTask task). I guess you are accidentally using an ExceutionListener, but that does not have a "create" event.

Related

MismatchingMessageCorrelationException : Cannot correlate message ‘onEventReceiver’: No process definition or execution matches the parameters

We are facing an MismatchingMessageCorrelationException for the receive task in some cases (less than 5%)
The call back to notify receive task is done by :
protected void respondToCallWorker(
#NonNull final String correlationId,
final CallWorkerResultKeys result,
#Nullable final Map<String, Object> variables
) {
try {
runtimeService.createMessageCorrelation("callWorkerConsumer")
.processInstanceId(correlationId)
.setVariables(variables)
.setVariable("callStatus", result.toString())
.correlateWithResult();
} catch(Exception e) {
e.printStackTrace();
}
}
When i check the logs : i found that the query executed is this one :
select distinct RES.* from ACT_RU_EXECUTION RES
inner join ACT_RE_PROCDEF P on RES.PROC_DEF_ID_ = P.ID_
WHERE RES.PROC_INST_ID_ = 'b2362197-3bea-11eb-a150-9e4bf0efd6d0' and RES.SUSPENSION_STATE_ = '1'
and exists (select ID_ from ACT_RU_EVENT_SUBSCR EVT
where EVT.EXECUTION_ID_ = RES.ID_ and EVT.EVENT_TYPE_ = 'message'
and EVT.EVENT_NAME_ = 'callWorkerConsumer' )
Some times, When i look for the instance of the process in the database i found it waiting in the receive task
SELECT DISTINCT * FROM ACT_RU_EXECUTION RES
WHERE id_ = 'b2362197-3bea-11eb-a150-9e4bf0efd6d0'
However, when i check the subscription event, it's not yet created in the database
select ID_ from ACT_RU_EVENT_SUBSCR EVT
where EVT.EXECUTION_ID_ = 'b2362197-3bea-11eb-a150-9e4bf0efd6d0'
and EVT.EVENT_TYPE_ = 'message'
and EVT.EVENT_NAME_ = 'callWorkerConsumer'
I think that the solution is to save the "receive task" before getting the response for respondToCallWorker, but sadly i can't figure it out.
I tried "asynch before" callWorker and "Message consumer" but it did not work,
I also tried camunda.bpm.database.jdbc-batch-processing=false and got the same results,
I tried also parallel branches but i get OptimisticLocak exception and MismatchingMessageCorrelationException
Maybe i am doing it wrong
Thanks for your help
This is an interesting problem. As you already found out, the error happens, when you try to correlate the result from the "worker" before the main process ended its transaction, thus there is no message subscription registered at the time you correlate.
This problem in process orchestration is described and analyzed in this blog post, which is definitely worth reading.
Taken from that post, here is a design that should solve the issue:
You make message send and receive parallel and put an async before the send task.
By doing so, the async continuation job for the send event and the message subscription are written in the same transaction, so when the async message send executes, you already have the subscription waiting.
Although this should work and solve the issue on BPMN model level, it might be worth to consider options that do not require remodeling the process.
First, instead of calling the worker directly from your delegate, you could (assuming you are on spring boot) publish a "CallWorkerCommand" (simple pojo) and use a TransactionalEventLister on a spring bean to execute the actual call. By doing so, you first will finish the BPMN process by subscribing to the message and afterwards, spring will execute your worker call.
Second: you could use a retry mechanism like resilience4j around your correlate message call, so in the rare cases where the result comes to quickly, you fail and retry a second later.
Another solution I could think of, since you seem to be using an "external worker" pattern here, is to use an external-task-service task directly, so the send/receive synchronization gets solved by the Camunda external worker API.
So many options to choose from. I would possibly prefer the external task, followed by the transactionalEventListener, but that is a matter of personal preference.

Camunda delegateExecution's getVariable throws ENGINE-03040 No serializer defined for variable instance

I'm new to Camunda. I've defined BPMN for set of tasks. Created necessary delegates to handle the activities.
As a business process I need to check pre qualification to proceed to next activity. If pre qualification fails I need to wait and periodically check for the pre qualification conditions. The flow succeeds if the pre qualification is true in the first run itself. If the pre qualification is false, Camunda waits for 2 seconds and triggers for pre qualification activity, while doing so I get following error and the instance fails.
Stacktrace:
org.camunda.bpm.engine.ProcessEngineException: ENGINE-03040 No serializer defined for variable instance 'org.camunda.bpm.engine.impl.persistence.entity.util.TypedValueField#44ba275a'
at org.camunda.bpm.engine.impl.db.EnginePersistenceLogger.serializerNotDefinedException(EnginePersistenceLogger.java:387)
at org.camunda.bpm.engine.impl.persistence.entity.util.TypedValueField.ensureSerializerInitialized(TypedValueField.java:207)
at org.camunda.bpm.engine.impl.persistence.entity.util.TypedValueField.getSerializer(TypedValueField.java:194)
at org.camunda.bpm.engine.impl.persistence.entity.util.TypedValueField.getTypedValue(TypedValueField.java:105)
at org.camunda.bpm.engine.impl.persistence.entity.VariableInstanceEntity.getTypedValue(VariableInstanceEntity.java:276)
at org.camunda.bpm.engine.impl.core.variable.scope.AbstractVariableScope.getValueFromVariableInstance(AbstractVariableScope.java:146)
at org.camunda.bpm.engine.impl.core.variable.scope.AbstractVariableScope.getVariable(AbstractVariableScope.java:133)
at org.camunda.bpm.engine.impl.core.variable.scope.AbstractVariableScope.getVariable(AbstractVariableScope.java:129)
We are struggling on this for quite sometime now. Any help would be appreciated.
Thanks.
Saravan

Django Signals for task plannification

I try to found the best way to manage this issue with Django Signals:
I created a datamodel with a table ExecutionPlan
In this table I simply store task to execute at a "startDate" value.
I would like to be "signaled" when a "execution line" have a "startDate < Now"
I read Django documentation on signals but I didn't found any case where a signal is send for "a data value check", in my case when a startdate is outpassed.
So my question is more methodic than technical:
Do you think that Django Signals is designed for that case ?
Should I design my own event loop ?
Thanks in advance.
Cyril
You can create a cronjob that runs every X minutes (using django-cron for example) that checks if now>startDate and starts the task if needed.

Airflow task to refer to multiple previous tasks?

Is there a way I can have a task require the completion of multiple upstream tasks which are still able to finish independently?
download_fcr --> process_fcr --> load_fcr
download_survey --> process_survey --> load_survey
create_dashboard should require load_fcr and load_survey to successfully complete.
I do not want to force anything in the 'survey' task chain to require anything from the 'fcr' task chain to complete. I want them to process in parallel and still complete even if one fails. However, the dashboard task requires both to finish loading to the database before it should start.
fcr *-->*-->*
\
---> create_dashboard
/
survey *-->*-->*
You can pass a list of tasks to set_upstream or set_downstream. In your case, if you specifically want to use set_upstream, you could describe your dependencies as:
create_dashboard.set_upstream([load_fcr, load_survey])
load_fcr.set_upstream(process_fcr)
process_fcr.set_upstream(download_fcr)
load_survey.set_upstream(process_survey)
process_survey.set_upstream(download_survey)
Have a look at airflow's source code: even when you pass just one task object to set_upstream, it actually wraps a list around it before doing anything.
download_fcr.set_downstream(process_fcr)
process_fcr.set_downstream(load_fcr)
download_survey.set_downstream(process_survey)
process_survey.set_downstream(load_survey)
load_survey.set_downstream(create_dashboard)
load_fcr.set_downstream(create_dashboard)

Usage of send and receive task in camunda BPMN

I am using a send task to which the following Javadelegate class is attached.
public class SendTaskDelegate implements JavaDelegate {
public void execute(DelegateExecution execution) throws Exception {
execution.getProcessEngineServices()
.getRuntimeService()
.createMessageCorrelation("someMessage")
.processInstanceBusinessKey("someBusinessKey")
.correlate();
}
}
But I am getting this error::
An error happend while submitting the task form : Cannot submit task form c0e85bad-719f-11e5-94aa-d897baecf24a: Cannot correlate message someMessage: No process definition or execution matches the parameters
How can I debug it?
The error message says, that your JavaDelegate code just gets excuted correctly. The process engine tries to find a running process instance with 'someBusinessKey' as business key and currently waiting for a message 'someMessage', but does not find such an instance. Your code acts as if there were such an instance and you try to find it and tell it about a message. See the docs section about correlation methods - in principle the mechanism is used to 'route' a message to the correct instance targeting it.
As a sidenote: your JavaDelegate seems to get called in the same transaction with which you also try to complete a task. The "borders of transactions" in your process can be managed with 'async' attributes described in the docs section about transactions in processes.