How to finish all parallel activities ViewFlow (Terminate End)?

499 views Asked by At

I want release this flow: enter image description here

I tried use only one node End, but the other branch remains active. How to finish all active tasks and the whole process when finishes one branch?

2

There are 2 answers

0
Alejandro Sánchez On

What you need is called event based gateway in BPMN, and it is not supported by Viewflow out of the box, you have to implement the code provided by kmmbvnr.

enter image description here

What this gateway does, is to activate the outgoing paths and wait for any of the tasks to be completed, and when the first task is done, the other paths or tasks are cancelled.

When you are using flows that go back in one of the paths, you have to consider than no other paths are active, only the one than first completed a task.

0
kmmbvnr On

By a BPNM specification flow.End finishes only tasks tokens that comes into it. Parallel task stays unfinished.

If you have a situation where one of parallel flows need to be canceled, in BPMN such processes modeled by a complex split gateway that waits till on of there subsequent task finishes and cancels others. Here is the sketch implementation for a viewflow split-first node. You can adapt it for your specific case.

class SplitFirst(flow.Split):
    shape = {
        'width': 50,
        'height': 50,
        'svg': """
            <path class="gateway" d="M25,0L50,25L25,50L0,25L25,0"/>
        <text class="gateway-marker" font-size="32px" x="25" y="35">1</text>
        """
    }

    def on_signal(self, sender, **signal_kwargs):
        task = signal_kwargs['task']
        split_first = task.previous.filter(flow_task=self).first()
        if split_first:
            for leading in split_first.leading.all().exclude(pk=task.pk):
                activation = leading.activate()
                if hasattr(activation, 'cancel') and activation.cancel.can_proceed():
                    activation.cancel()

    def ready(self):
        super(SplitFirst, self).ready()

        task_finished.connect(
            self.on_signal,
            sender=self.flow_class,
            dispatch_uid="sample.splitfirst/{}.{}.{}".format(
                self.flow_class.__module__, self.flow_class.__name__, self.name
            )
        )