Do not delete canceled tasks (#2103)

* do not delete tasks that were canceled when we terminate a pi w/ burnettk

* added test to ensure pi can be terminated with subprocess w/ burnettk

---------

Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
jasquat 2024-10-09 11:58:39 -04:00 committed by GitHub
parent f88ec4961a
commit b1359e3083
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 108 additions and 2 deletions

View File

@ -1934,7 +1934,7 @@ class ProcessInstanceProcessor:
def remove_spiff_tasks_for_termination(self) -> None:
start_time = time.time()
deleted_tasks = self.bpmn_process_instance.cancel() or []
self.bpmn_process_instance.cancel()
spiff_tasks = self.bpmn_process_instance.get_tasks()
task_service = TaskService(
@ -1944,7 +1944,7 @@ class ProcessInstanceProcessor:
bpmn_subprocess_mapping=self.bpmn_subprocess_mapping,
task_model_mapping=self.task_model_mapping,
)
task_service.update_all_tasks_from_spiff_tasks(spiff_tasks, deleted_tasks, start_time)
task_service.update_all_tasks_from_spiff_tasks(spiff_tasks, [], start_time)
# we may want to move this to task_service.update_all_tasks_from_spiff_tasks,
# but not sure it's always good to it.

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:process id="Process_subprocess_with_manual_task_jhbet6z" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_17db3yp</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_17db3yp" sourceRef="StartEvent_1" targetRef="Activity_subprocess_task_in_level_1" />
<bpmn:endEvent id="EndEvent_1">
<bpmn:incoming>Flow_12pkbxb</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_12pkbxb" sourceRef="Activity_subprocess_task_in_level_1" targetRef="EndEvent_1" />
<bpmn:subProcess id="Activity_subprocess_task_in_level_1" name="subprocess">
<bpmn:extensionElements>
<spiffworkflow:instructionsForEndUser>This is an example **Manual Task**. A **Manual Task** is designed to allow someone to complete a task outside of the system and then report back that it is complete. You can click the *Continue* button to proceed. When you are done running this process, you can edit the **Process Model** to include a:
* **Script Task** - write a short snippet of python code to update some data
* **User Task** - generate a form that collects information from a user
* **Service Task** - communicate with an external API to fetch or update some data.
You can also change the text you are reading here by updating the *Instructions* on this example manual task.</spiffworkflow:instructionsForEndUser>
</bpmn:extensionElements>
<bpmn:incoming>Flow_17db3yp</bpmn:incoming>
<bpmn:outgoing>Flow_12pkbxb</bpmn:outgoing>
<bpmn:startEvent id="Event_1223lmx">
<bpmn:outgoing>Flow_1j4qlo8</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_1j4qlo8" sourceRef="Event_1223lmx" targetRef="manual_task_in_level_2" />
<bpmn:endEvent id="Event_0jjaa23">
<bpmn:incoming>Flow_0rqseh5</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0rqseh5" sourceRef="manual_task_in_level_2" targetRef="Event_0jjaa23" />
<bpmn:manualTask id="manual_task_in_level_2" name="manual task">
<bpmn:incoming>Flow_1j4qlo8</bpmn:incoming>
<bpmn:outgoing>Flow_0rqseh5</bpmn:outgoing>
</bpmn:manualTask>
</bpmn:subProcess>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_subprocess_with_manual_task_jhbet6z">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_14za570_di" bpmnElement="EndEvent_1">
<dc:Bounds x="432" y="159" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0a0d8n5_di" bpmnElement="Activity_subprocess_task_in_level_1">
<dc:Bounds x="270" y="137" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_17db3yp_di" bpmnElement="Flow_17db3yp">
<di:waypoint x="215" y="177" />
<di:waypoint x="270" y="177" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_12pkbxb_di" bpmnElement="Flow_12pkbxb">
<di:waypoint x="370" y="177" />
<di:waypoint x="432" y="177" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
<bpmndi:BPMNDiagram id="BPMNDiagram_0nn5nzq">
<bpmndi:BPMNPlane id="BPMNPlane_0860qye" bpmnElement="Activity_subprocess_task_in_level_1">
<bpmndi:BPMNShape id="Event_1223lmx_di" bpmnElement="Event_1223lmx">
<dc:Bounds x="332" y="192" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0jjaa23_di" bpmnElement="Event_0jjaa23">
<dc:Bounds x="572" y="192" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1rm8aci_di" bpmnElement="manual_task_in_level_2">
<dc:Bounds x="420" y="170" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1j4qlo8_di" bpmnElement="Flow_1j4qlo8">
<di:waypoint x="368" y="210" />
<di:waypoint x="420" y="210" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0rqseh5_di" bpmnElement="Flow_0rqseh5">
<di:waypoint x="520" y="210" />
<di:waypoint x="572" y="210" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -1136,6 +1136,31 @@ class TestProcessInstanceProcessor(BaseTest):
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
assert process_instance.status == ProcessInstanceStatus.complete.value
def test_can_terminate_instance_with_subprocess(
self,
app: Flask,
client: FlaskClient,
with_db_and_bpmn_file_cleanup: None,
) -> None:
self.create_process_group("test_group", "test_group")
initiator_user = self.find_or_create_user("initiator_user")
finance_user_three = self.find_or_create_user("testuser3")
assert initiator_user.principal is not None
assert finance_user_three.principal is not None
AuthorizationService.import_permissions_from_yaml_file()
finance_group = GroupModel.query.filter_by(identifier="Finance Team").first()
assert finance_group is not None
process_model = load_test_spec(
process_model_id="test_group/subprocess_with_manual_task",
process_model_source_directory="subprocess_with_manual_task",
)
process_instance = self.create_process_instance_from_process_model(process_model=process_model, user=initiator_user)
processor = ProcessInstanceProcessor(process_instance)
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
processor.terminate()
# # To test processing times with multiinstance subprocesses
# def test_large_multiinstance(
# self,