2022-10-12 10:19:53 -04:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
# Copyright (C) 2012 Matthew Hampton
|
|
|
|
#
|
|
|
|
# This library is free software; you can redistribute it and/or
|
|
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
|
|
# License as published by the Free Software Foundation; either
|
|
|
|
# version 2.1 of the License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This library is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
# Lesser General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
|
|
# License along with this library; if not, write to the Free Software
|
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
|
|
# 02110-1301 USA
|
|
|
|
|
|
|
|
from ...task import TaskState
|
|
|
|
from .BpmnSpecMixin import BpmnSpecMixin
|
|
|
|
from ...specs.Join import Join
|
|
|
|
|
|
|
|
|
|
|
|
class UnstructuredJoin(Join, BpmnSpecMixin):
|
|
|
|
"""
|
|
|
|
A helper subclass of Join that makes it work in a slightly friendlier way
|
|
|
|
for the BPMN style threading
|
|
|
|
"""
|
|
|
|
def _get_inputs_with_tokens(self, my_task):
|
|
|
|
# Look at the tree to find all places where this task is used.
|
2023-01-26 18:17:35 -05:00
|
|
|
tasks = [ t for t in my_task.workflow.get_tasks_from_spec_name(self.name) if t.workflow == my_task.workflow ]
|
2022-10-12 10:19:53 -04:00
|
|
|
|
2023-01-26 18:17:35 -05:00
|
|
|
# Look up which tasks have parents completed.
|
2022-10-12 10:19:53 -04:00
|
|
|
waiting_tasks = []
|
|
|
|
completed_inputs = set()
|
|
|
|
for task in tasks:
|
2023-01-26 18:17:35 -05:00
|
|
|
if task.parent.state == TaskState.COMPLETED:
|
2022-10-12 10:19:53 -04:00
|
|
|
completed_inputs.add(task.parent.task_spec)
|
2023-01-26 18:17:35 -05:00
|
|
|
# Ignore predicted tasks; we don't care about anything not definite
|
|
|
|
elif task.parent._has_state(TaskState.READY | TaskState.FUTURE | TaskState.WAITING):
|
2022-10-12 10:19:53 -04:00
|
|
|
waiting_tasks.append(task.parent)
|
|
|
|
|
|
|
|
return completed_inputs, waiting_tasks
|
|
|
|
|
|
|
|
def _do_join(self, my_task):
|
2023-01-26 18:17:35 -05:00
|
|
|
split_task = self._get_split_task(my_task)
|
2022-10-12 10:19:53 -04:00
|
|
|
|
|
|
|
# Identify all corresponding task instances within the thread.
|
|
|
|
# Also remember which of those instances was most recently changed,
|
|
|
|
# because we are making this one the instance that will
|
|
|
|
# continue the thread of control. In other words, we will continue
|
|
|
|
# to build the task tree underneath the most recently changed task.
|
|
|
|
last_changed = None
|
|
|
|
thread_tasks = []
|
|
|
|
for task in split_task._find_any(self):
|
|
|
|
if task.thread_id != my_task.thread_id:
|
2023-04-07 11:46:14 -04:00
|
|
|
# Ignore tasks from other threads. (Do we need this condition?)
|
2022-10-12 10:19:53 -04:00
|
|
|
continue
|
|
|
|
if not task.parent._is_finished():
|
2023-04-07 11:46:14 -04:00
|
|
|
# For an inclusive join, this can happen - it's a future join
|
|
|
|
continue
|
|
|
|
if my_task._is_descendant_of(task):
|
|
|
|
# Skip ancestors (otherwise the branch this task is on will get dropped)
|
2022-10-12 10:19:53 -04:00
|
|
|
continue
|
|
|
|
# We have found a matching instance.
|
|
|
|
thread_tasks.append(task)
|
|
|
|
|
2023-01-26 18:17:35 -05:00
|
|
|
# Check whether the state of the instance was recently changed.
|
2022-10-12 10:19:53 -04:00
|
|
|
changed = task.parent.last_state_change
|
2023-01-26 18:17:35 -05:00
|
|
|
if last_changed is None or changed > last_changed.parent.last_state_change:
|
2022-10-12 10:19:53 -04:00
|
|
|
last_changed = task
|
|
|
|
|
|
|
|
# Update data from all the same thread tasks.
|
|
|
|
thread_tasks.sort(key=lambda t: t.parent.last_state_change)
|
2023-01-26 18:17:35 -05:00
|
|
|
collected_data = {}
|
2022-10-12 10:19:53 -04:00
|
|
|
for task in thread_tasks:
|
2023-01-26 18:17:35 -05:00
|
|
|
collected_data.update(task.data)
|
2022-10-12 10:19:53 -04:00
|
|
|
|
|
|
|
for task in thread_tasks:
|
2023-04-07 11:46:14 -04:00
|
|
|
if task != last_changed:
|
|
|
|
task._set_state(TaskState.CANCELLED)
|
2022-10-12 10:19:53 -04:00
|
|
|
task._drop_children()
|
2023-04-07 11:46:14 -04:00
|
|
|
else:
|
|
|
|
task.data.update(collected_data)
|
|
|
|
|
2022-10-12 10:19:53 -04:00
|
|
|
def task_should_set_children_future(self, my_task):
|
|
|
|
return True
|
|
|
|
|
|
|
|
def task_will_set_children_future(self, my_task):
|
|
|
|
# go find all of the gateways with the same name as this one,
|
|
|
|
# drop children and set state to WAITING
|
|
|
|
for t in list(my_task.workflow.task_tree):
|
|
|
|
if t.task_spec.name == self.name and t.state == TaskState.COMPLETED:
|
|
|
|
t._set_state(TaskState.WAITING)
|