Go back to previous user task

I have a use case where I need to use a “Back” button to go back to previous user task programmatically.

Assume that same user runs a single process and completes user tasks from start to end.

START => UserTask-A => UserTask-B => UserTask-C => END

At any point in the flow, user can click on a “Back” button and the process should go back to previous UserTask.

I can not use extra transitions in the model builder to go back, because I have giant flows and this needs to be done programmatically via spring service beans like TaskService, RuntimeService, etc.

Is this possible ? Or any suggestions to implement this functionality ?

Can you upload your model or enough of the model so that we can visualize what you’re trying to do.

Also is it a service that decides to “go back” or a user?
What is the reason for going back? an error? undoing something?

The reason for going back depends on user choice. See below sample model (which is a very basic one to explain the need).

If user completes the first task with “taskNotValid” option and realizes this was not correct, he/she needs to go back to choose the option “taskValid”. I need an api call to do that, I can store the previous task data in my backend.

This post helped me to achieve this. Process modification works perfectly.

What I did to achieve this is to store the transitionId of the previous userTask in the session, so when the user clicks on the back button, below code runs and it goes back to the previous user task.

You need to find the current activityInstanceId as well, and I assume you already know the process instance id.

String activityInstanceId = null;

ActivityInstance activityInstance = runtimeService.getActivityInstance(processInstanceId);
if(activityInstance != null){
	if(activityInstance.getChildActivityInstances() != null){
		ActivityInstance childActivityInstance= activityInstance.getChildActivityInstances()[0];
		activityInstanceId = childActivityInstance.getId();
	}
};

runtimeService.createProcessInstanceModification(processInstanceId)
					.cancelActivityInstance(activityInstanceId)
					.startTransition(transitionId)
					.execute();
1 Like

Hi there, I realise this is an old post but I was wondering how you got the transition id of the previous task ?

Thanks

@aminmc Lets assume you want to go back from step 2 in below flow, then you need to find the transition id of transition1. This would help you run a modification to have that process continue from transition1 which leads to step 1. So your process goes back to step 1.

I have a bpmn parse listener as below. Bpmn parse listener only runs once after a new process definition deployed. This helps me to detect the transitions which target a userTask and I cache them in a map with the relating userTaskId. You don’t have to do this if you can afford the time required to parse your process definition file and find the transition id every time you run a new process instance. In that case, I guess you need to use repositoryService to parse the bpmn file.

import org.camunda.bpm.engine.RepositoryService;

So whenever I hit a userTask, I find the targeting transitionId and store it in the session and use it in case I need to go to previous userTask.


import org.camunda.bpm.engine.impl.bpmn.parser.AbstractBpmnParseListener;
import org.camunda.bpm.engine.impl.bpmn.parser.BpmnParseListener;

@Slf4j
@Service
public class SolidBpmnParseListener extends AbstractBpmnParseListener implements BpmnParseListener {

	private boolean isActivityOfTypeUserTask (ActivityImpl activity){
		return activity != null && activity.getProperty("type") != null &&
				activity.getProperty("type").toString().equals("userTask");
	}

	@Override
	public void parseSequenceFlow(Element sequenceFlowElement, ScopeImpl scopeElement, TransitionImpl transition) {
		try {
			// if sequence destination is usertask
			PvmActivity destinationPvmActivity = transition.getDestination();
			if(destinationPvmActivity instanceof ActivityImpl) {
				ActivityImpl destinationActivity = (ActivityImpl)destinationPvmActivity;
				if (isActivityOfTypeUserTask(destinationActivity)) {
                    // you have a transition targeting to a user task
					handleSequenceForDestination(transition); 

				}
			}
		} catch (Exception e) {
			log.error("Failed parseSequenceFlow.", e);
		}
	}
}
1 Like

Thank you @guvenc