mirror of
https://github.com/status-im/spiff-arena.git
synced 2025-02-11 01:06:36 +00:00
ba67d7ad34
98c6294f1 Merge pull request #287 from sartography/feature/workflow_data_exceptions d40a1da59 Workflow Data Exceptions were broken in the previous error refactor. This assures we are getting good messages from these errors. a156378e1 Merge pull request #286 from sartography/feature/inclusive-gateway-support 7f6e398c2 bypass unnecessary checks in gateway joins ade21a894 revert a few things e1cf75202 Merge branch 'main' into feature/inclusive-gateway-support 15a0a4414 revert change to MultiChoice and handle no defaults in BPMN specs e1469e6bb add support for diverging inclusive gateways 71fd86386 really prevent non-default flows without conditions 924759d9b clean up join specs 7378639d3 Merge pull request #284 from sartography/feature/improved-timer-events dc8d139d2 remove useless method 530f23697 Merge branch 'main' into feature/improved-timer-events 307cca9c5 partially clean up existing gateways 0a344285e clean up task parsers 2cef997d1 add waiting_events method to bpmn workflow 48091c407 serializer migration script and miscellaneous fixes to serialization 61316854b store internal timer data as string/float 389c14c4c add some tests for parsing durations 582bc9482 convert timers to iso 8601 6dfd7ebe9 remove extraneous calls to update 6bd429529 clean up tests d56e9912f remove useless method git-subtree-dir: SpiffWorkflow git-subtree-split: 98c6294f1240aee599cd98bcee58d121cb57b331
103 lines
4.3 KiB
Python
103 lines
4.3 KiB
Python
# -*- 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.
|
|
tasks = [ t for t in my_task.workflow.get_tasks_from_spec_name(self.name) if t.workflow == my_task.workflow ]
|
|
|
|
# Look up which tasks have parents completed.
|
|
waiting_tasks = []
|
|
completed_inputs = set()
|
|
for task in tasks:
|
|
if task.parent.state == TaskState.COMPLETED:
|
|
completed_inputs.add(task.parent.task_spec)
|
|
# Ignore predicted tasks; we don't care about anything not definite
|
|
elif task.parent._has_state(TaskState.READY | TaskState.FUTURE | TaskState.WAITING):
|
|
waiting_tasks.append(task.parent)
|
|
|
|
return completed_inputs, waiting_tasks
|
|
|
|
def _do_join(self, my_task):
|
|
split_task = self._get_split_task(my_task)
|
|
|
|
# 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):
|
|
# Ignore tasks from other threads.
|
|
if task.thread_id != my_task.thread_id:
|
|
continue
|
|
# Ignore my outgoing branches.
|
|
if self.split_task and task._is_descendant_of(my_task):
|
|
continue
|
|
# For an inclusive join, this can happen - it's a future join
|
|
if not task.parent._is_finished():
|
|
continue
|
|
# We have found a matching instance.
|
|
thread_tasks.append(task)
|
|
|
|
# Check whether the state of the instance was recently changed.
|
|
changed = task.parent.last_state_change
|
|
if last_changed is None or changed > last_changed.parent.last_state_change:
|
|
last_changed = task
|
|
|
|
# Update data from all the same thread tasks.
|
|
thread_tasks.sort(key=lambda t: t.parent.last_state_change)
|
|
collected_data = {}
|
|
for task in thread_tasks:
|
|
collected_data.update(task.data)
|
|
|
|
# Mark the identified task instances as COMPLETED. The exception
|
|
# is the most recently changed task, for which we assume READY.
|
|
# By setting the state to READY only, we allow for calling
|
|
# :class:`Task.complete()`, which leads to the task tree being
|
|
# (re)built underneath the node.
|
|
for task in thread_tasks:
|
|
if task == last_changed:
|
|
task.data.update(collected_data)
|
|
self.entered_event.emit(my_task.workflow, my_task)
|
|
task._ready()
|
|
else:
|
|
task._set_state(TaskState.COMPLETED)
|
|
task._drop_children()
|
|
|
|
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)
|