Continue Receive Task through email activation link

347 views
Skip to first unread message

roleba...@gmail.com

unread,
Feb 18, 2016, 4:52:09 AM2/18/16
to camunda BPM users
Scenario:
Within a multi-instance subprocess I have a call-activity called "email-verification". This activity contains a Receive Task which should be continued when a user clicks on the activation-link (which has been send per e-mail to the user before).

Questions:
- Is it a good idea to use the processInstanceId for generating the email-activation link?
- How to identify the waiting receive task by a given processInstanceId? Using ExecutionQuery, ProcessInstanceQuery or something else?
- How to pass data to the waiting receive task and continue it using the Java API?
- Does the following sentence mean that my scenario is not possible? "Correlation of a parallel multi instance isn’t possible because the subscription can’t be identified unambiguously."
- When the built-in message correlation does not work is it still possible using other methods?
- In order to access process engine services from within a different webapp (inside the same servlet container) I need to retrieve an instance of the shared process engine API in first place. How to access the shared engine correctly?
- Which characteristics does a process service instances (i.e. RuntimeService) have? Is it thread-safe, a Singleton, ThreadLocal or something else? I couldn't find answers in the Javadoc for this[2]

[1] https://docs.camunda.org/manual/7.4/reference/bpmn20/tasks/receive-task/
[2] https://docs.camunda.org/javadoc/camunda-bpm-platform/7.4/

Philipp Ossler

unread,
Feb 19, 2016, 9:58:08 AM2/19/16
to camunda BPM users, roleba...@gmail.com
Hi,

can you please share your processes for better understanding.

However, I try to answer your questings as good as I can:

- Is it a good idea to use the processInstanceId for generating the email-activation link?

If each receive task have a unique process instance id then you can use it for correlation. In case you use a parallel multi-instance embedded subprocess which contains the receive task then the id is not unique and you can't trigger a specific receive task. 
 
- How to identify the waiting receive task by a given processInstanceId? Using ExecutionQuery, ProcessInstanceQuery or something else?

As mentioned before, you can not use the process instance id if it is not unique. You can use the execution id of the receive task or set a unique variable to identify the specific task. Using the execution id, you can trigger the task by the messageEventReceived() method from runtime service. If you want to use a variable then you should query the event subscription first.
 
- How to pass data to the waiting receive task and continue it using the Java API? 

If you use the  messageEventReceived() method of the runtime service then you can pass variables as payload. When the message is received then the variable are set on the execution.
 
- Does the following sentence mean that my scenario is not possible? "Correlation of a parallel multi instance isn’t possible because the subscription can’t be identified unambiguously."

This means that you can not use the message correlation API (i.e. createMessageCorrelation(...)) since you can not use an execution id or local variables of a execution to correlate a message.
 
- When the built-in message correlation does not work is it still possible using other methods?

As mentioned before, you can trigger the task explicit using messageEventReceived() or signal() method of the runtime service.
 

Greetings,
Philipp

roleba...@gmail.com

unread,
Feb 19, 2016, 12:38:08 PM2/19/16
to camunda BPM users, roleba...@gmail.com
Yes, the outer process is marked as "parallel". As far as I understood your answer the receive task should be identified by the executionId instead of the process instance id in this case. This rises another question:

- Do subprocesses inherit the process instance id of their parent process?

The RuntimeService method messageEventReceived() seems to be the solution. But this rises additional questions:
- Generally asked: Is the executionId an identification on the lowest possible layer thus any receive task could be uniquily identified this way?
- What does the receive task need in order to be triggerable by messageEventReceived()? Does it need an signal boundary event or is the message definition+name sufficient?
- Regarding the docs [3] the Execution concept in the process engine is not completely aligned with the activity instance concept and it is not guaranteed that the same execution that started a given activity instance will also end it. Does it mean that the executionId is not guaranteed to work as expected?

[3] https://docs.camunda.org/manual/7.4/user-guide/process-engine/process-engine-concepts/#relation-to-executions

Philipp Ossler

unread,
Feb 22, 2016, 5:00:49 AM2/22/16
to camunda BPM users, roleba...@gmail.com
Hi,
 

- Do subprocesses inherit the process instance id of their parent process?


Yes, an embedded sub-process has the same process instance id since it is still the same process instance. If you use a call activity to start a (re-usable) subprocess then the create instance has a different process instance id.
 

- Generally asked: Is the executionId an identification on the lowest possible layer thus any receive task could be uniquily identified this way?


Since a process instance can have multiple executions, the execution is the lowest layer in the execution tree. Please refer to [1] if you are interested in details about the execution tree. 
In your case, any receive task have a unique execution id.
  

- What does the receive task need in order to be triggerable by messageEventReceived()? Does it need an signal boundary event or is the message definition+name sufficient?


If the receive task reference a message event definition then you can use the messageEventReceived() method. [2]
 

- Regarding the docs [3] the Execution concept in the process engine is not completely aligned with the activity instance concept and it is not guaranteed that the same execution that started a given activity instance will also end it. Does it mean that the executionId is not guaranteed to work as expected?


Depending on your expectations ;) However, you have to be aware that the execution id can change. For example, if your subprocess contains a task which sends the activation link and a receive task which should be triggered by message then the execution id of the message event subscription of the receive task is different from the one that triggers the first task. It is because of different scopes, see [1] for details.

So how can you trigger the receive task?

The easiest way is to use a separate process definition for the subprocess and call it via call activity [3]. In this case, you can identify the receive task with the process instance id or a process variable and you can trigger it using the correlation API.

Otherwise, you can use a local variable to identify the receive task. Note that the local variable must be set in the same execution, for example using an execution listener on the receive task.
Execution execution = runtimeService.createExecutionQuery().variableValueEquals("correlation-variable", "unique-correlation-id").singleResult();
runtimeService.messageEventReceived("messageOfReceiveTask", execution.getId());

Greetings,
Philipp

roleba...@gmail.com

unread,
Feb 22, 2016, 6:10:19 PM2/22/16
to camunda BPM users, roleba...@gmail.com
Thank you very much! Your explanation and support helps me a lot. So I have only a view questions left.

Now I am trying to find a concrete solution for the following model. I have created a simplified version of it retaining the overall structure: http://postimg.org/image/yac6anggj/

> Note that the local variable must be set in the same execution, for example using an execution listener on the receive task.

- Does the developer have to explicitly set the variable as "local"? I am not sure what happens when the process instance already contains a variable with the same name or if the developer uses the DelegateExecution method setVariable() instead of setVariableLocal()
- I don't think that the method variableValueEquals(String name, Object value) could guarantee a unique result (execution) if the correlation-value equals the email address for example because the user might be able to register twice using the same address. Do you think that correlation-value should better be set to the execution id of the the recieve task?
- Most important question: Does the method variableValueEquals() solve the problem of having no guarantee that the receive task will be completed by the same execution which started it? And even if the excution id differs from the correlation-value used for searching it the receive task would still be identifed uniquely and correctly?
- Would I be correct in saying that the execution id as returned by variableValueEquals().singleResult() will remain the same until the receive task gets actually triggered just one line futher?

At the moment my model contains a seperate task to send the activation email to the user. But as far as I understood your note ("the local variable must be set in the same execution") it is not safe to generate a activation-link based on an execution id other than the receive task. This means that my model would not work because I generate the activation link based on the execution id of the sending task (which is different to the receive task). At the moment I see two possibilites:

1. Programmatically generate a strong uid in the sending task, set it as a process variable and use the method processVariableValueEquals to find the correct execution id for identifying the receive task (which would require to handle a list of executions; further introducing complexity)
2. Change the model in some way which allows to generate the activation link based on the execution id of the receive task. At the moment I have no idea how such a model would look like because the activation-email logically has to be send to the user before the receive task gets entered

Both ways seems to introduce additional complexity. What do you think?

Furthermore I have found no answers in the docs for this questions:
- "All entities that can have variables are called variable scopes." [1] Which entities can have variables?
- Is there difference between a scope and an execution?
- Can a non-scope activity store variables?

[1] https://docs.camunda.org/manual/7.4/user-guide/process-engine/variables/#variable-scopes-and-variable-visibility

webcyberrob

unread,
Feb 22, 2016, 10:05:21 PM2/22/16
to camunda BPM users, roleba...@gmail.com
Hi,

One other wrinkle to think about. Are your use cases workforce or external users? The reason I raise this is if you expose this function to external users, you could be exposing the engine externally and thus to a denial of service attack. If its to workforce, possibly less risk, particularly if the link can only be used on a corporate network.

Heres a pattern Ive contemplated to protect against a denial of service attack, however its based on use of AWS services. Hence the approach is a service task generates a UUID to represent the context. Store this UUID in an AWS Dynamo table as a key and associate process instance ID, execution Id, additional attributes to support correlation. 

Create a Spring component to expose and process an external URL to accept the UUID.

Hence when the link is clicked in the email, lookup the UUID in the Dynamo DB and mark the record as used. Thus if there was a denial of service attack, AWS dynamo absorbs the load. Only current, valid token use cases get a chance to correlate to the process engine. If you allow the external world to attempt to correlate to the engine, you may need to think about resource limiting somewhere to avoid a DNOS against the process database... Another advantage of the proposed technique is you minimise the data exposed to the outside world, ie no engine internal ids, whilst using the engines' internal ids for the actual correlation...

regards

Rob

roleba...@gmail.com

unread,
Feb 23, 2016, 12:45:27 PM2/23/16
to camunda BPM users, roleba...@gmail.com
Thanks you for this wrinkle!

I like the solution you proposed. Are you pushing the correlation data from the Spring component to the engine or is the engine itself pulling the date from the database? When pushing is used the spring component has to interact with the API of the engine somehow. If this happens over internet there would still be a risk for a DoS. I guess your concept is pulling the data from a database which prevents most attacks. But how to protect the databse server?

My use case is intended for external users on the public internet. But I don't expose the engine to the internet, at least I don't want the REST API to be accessible. Instead I have a servlet based webapp (not a process application) for the public which calls the Java API of camunda internally using the Java API of the shared engine running on the same servlet container. So a DoS on the webapp would affect the whole server including the engine :(
This rises a view question:
- How to disable the REST API of camunda completely?
- Which other parts of cammunda should be taken into account?
- At which revenue does the mafia start to pinch money using DoS attacks in europe? (I only heard of it once)
- How to switch off-topic posts to a new discussion in google groups?

webcyberrob

unread,
Feb 23, 2016, 4:08:25 PM2/23/16
to camunda BPM users, roleba...@gmail.com
Hi,
For public facing sites like your proposal, I would typically use a zoned three tier architecture;

(DMZ) -->Web --> App --> DB

where each zone only trusts the zone before it. Thus I would put the Camunda engine in the app zone and our servlet in the web zone. Between the zones you can IP address whitelist or similar and thus you can protect the engine's rest API by zoning the network...

Now you just have limit requests passed through from the web tier. Your choice here is either resource limit the web tier or filter out malicious requests. The approach I previously talked to effectively filters out the malicious requests by using something like Dynamo DB with very large scale to perform this filtering. Hence if a valid token is found in the Dynamo DB, then the servlet makes a REST call to the engine to correlate the message...

The approach you take depends. Resource limiting may be cheaper and easier, but is only effective if you have a small external user population. If you anticipate a large external user population, resource limiting will kill the user experience, hence use some sort of filtering technique to sort the good from the bad...

Hope this makes sense,

Rob
Reply all
Reply to author
Forward
0 new messages