ensure we remove corresponding bpmn processes when removing tasks from a process reset
This commit is contained in:
parent
7c555c62a4
commit
7ef3e62207
|
@ -10,11 +10,11 @@ set -o errtrace -o errexit -o nounset -o pipefail
|
||||||
mysql -uroot spiffworkflow_backend_unit_testing -e '
|
mysql -uroot spiffworkflow_backend_unit_testing -e '
|
||||||
select * from process_instance;
|
select * from process_instance;
|
||||||
|
|
||||||
select t.guid as task_guid, t.state as task_state, td.bpmn_identifier as task_id from task t
|
select t.guid as task_guid, t.state as task_state, td.bpmn_identifier as task_id, t.properties_json from task t
|
||||||
join task_definition td on td.id = t.task_definition_id
|
join task_definition td on td.id = t.task_definition_id
|
||||||
where process_instance_id=(select max(id) from process_instance);
|
where process_instance_id=(select max(id) from process_instance);
|
||||||
|
|
||||||
select bp.guid as bp_guid, bpd.bpmn_identifier as bp_identifier from bpmn_process bp
|
select bp.guid as bp_guid, bpd.bpmn_identifier as bp_identifier, bp.properties_json from bpmn_process bp
|
||||||
join bpmn_process_definition bpd on bpd.id = bp.bpmn_process_definition_id
|
join bpmn_process_definition bpd on bpd.id = bp.bpmn_process_definition_id
|
||||||
join bpmn_process bpb on bpb.id = bp.direct_parent_process_id
|
join bpmn_process bpb on bpb.id = bp.direct_parent_process_id
|
||||||
join process_instance pi on bpb.id = pi.bpmn_process_id
|
join process_instance pi on bpb.id = pi.bpmn_process_id
|
||||||
|
|
|
@ -1207,15 +1207,18 @@ class ProcessInstanceProcessor:
|
||||||
process_instance, ProcessInstanceEventType.process_instance_rewound_to_task.value, task_guid=to_task_guid
|
process_instance, ProcessInstanceEventType.process_instance_rewound_to_task.value, task_guid=to_task_guid
|
||||||
)
|
)
|
||||||
processor = ProcessInstanceProcessor(process_instance)
|
processor = ProcessInstanceProcessor(process_instance)
|
||||||
deleted_tasks = processor.bpmn_process_instance.reset_from_task_id(UUID(to_task_guid))
|
initial_spiff_tasks = processor.bpmn_process_instance.get_tasks()
|
||||||
spiff_tasks = processor.bpmn_process_instance.get_tasks()
|
|
||||||
|
processor.bpmn_process_instance.reset_from_task_id(UUID(to_task_guid))
|
||||||
|
current_spiff_tasks = processor.bpmn_process_instance.get_tasks()
|
||||||
|
deleted_spiff_tasks = [t for t in initial_spiff_tasks if t not in current_spiff_tasks]
|
||||||
|
|
||||||
task_service = TaskService(
|
task_service = TaskService(
|
||||||
process_instance=processor.process_instance_model,
|
process_instance=processor.process_instance_model,
|
||||||
serializer=processor._serializer,
|
serializer=processor._serializer,
|
||||||
bpmn_definition_to_task_definitions_mappings=processor.bpmn_definition_to_task_definitions_mappings,
|
bpmn_definition_to_task_definitions_mappings=processor.bpmn_definition_to_task_definitions_mappings,
|
||||||
)
|
)
|
||||||
task_service.update_all_tasks_from_spiff_tasks(spiff_tasks, deleted_tasks, start_time)
|
task_service.update_all_tasks_from_spiff_tasks(current_spiff_tasks, deleted_spiff_tasks, start_time)
|
||||||
|
|
||||||
# Save the process
|
# Save the process
|
||||||
processor.save()
|
processor.save()
|
||||||
|
@ -1662,9 +1665,7 @@ class ProcessInstanceProcessor:
|
||||||
"""Complete_task."""
|
"""Complete_task."""
|
||||||
task_model = TaskModel.query.filter_by(guid=human_task.task_id).first()
|
task_model = TaskModel.query.filter_by(guid=human_task.task_id).first()
|
||||||
if task_model is None:
|
if task_model is None:
|
||||||
raise TaskNotFoundError(
|
raise TaskNotFoundError(f"Cannot find a task with guid {human_task.task_id}")
|
||||||
f"Cannot find a task with guid {self.process_instance_model.id} and task_id is {human_task.task_id}"
|
|
||||||
)
|
|
||||||
|
|
||||||
task_model.start_in_seconds = time.time()
|
task_model.start_in_seconds = time.time()
|
||||||
self.bpmn_process_instance.run_task_from_id(spiff_task.id)
|
self.bpmn_process_instance.run_task_from_id(spiff_task.id)
|
||||||
|
|
|
@ -29,6 +29,7 @@ from spiffworkflow_backend.models.process_instance_event import ProcessInstanceE
|
||||||
from spiffworkflow_backend.models.spec_reference import SpecReferenceCache
|
from spiffworkflow_backend.models.spec_reference import SpecReferenceCache
|
||||||
from spiffworkflow_backend.models.spec_reference import SpecReferenceNotFoundError
|
from spiffworkflow_backend.models.spec_reference import SpecReferenceNotFoundError
|
||||||
from spiffworkflow_backend.models.task import TaskModel # noqa: F401
|
from spiffworkflow_backend.models.task import TaskModel # noqa: F401
|
||||||
|
from spiffworkflow_backend.models.task import TaskNotFoundError
|
||||||
from spiffworkflow_backend.models.task_definition import TaskDefinitionModel
|
from spiffworkflow_backend.models.task_definition import TaskDefinitionModel
|
||||||
from spiffworkflow_backend.services.process_instance_tmp_service import ProcessInstanceTmpService
|
from spiffworkflow_backend.services.process_instance_tmp_service import ProcessInstanceTmpService
|
||||||
|
|
||||||
|
@ -456,17 +457,27 @@ class TaskService:
|
||||||
def update_all_tasks_from_spiff_tasks(
|
def update_all_tasks_from_spiff_tasks(
|
||||||
self, spiff_tasks: list[SpiffTask], deleted_spiff_tasks: list[SpiffTask], start_time: float
|
self, spiff_tasks: list[SpiffTask], deleted_spiff_tasks: list[SpiffTask], start_time: float
|
||||||
) -> None:
|
) -> None:
|
||||||
|
"""Update given spiff tasks in the database and remove deleted tasks."""
|
||||||
# Remove all the deleted/pruned tasks from the database.
|
# Remove all the deleted/pruned tasks from the database.
|
||||||
deleted_task_ids = list(map(lambda t: str(t.id), deleted_spiff_tasks))
|
deleted_task_guids = list(map(lambda t: str(t.id), deleted_spiff_tasks))
|
||||||
tasks_to_clear = TaskModel.query.filter(TaskModel.guid.in_(deleted_task_ids)).all() # type: ignore
|
tasks_to_clear = TaskModel.query.filter(TaskModel.guid.in_(deleted_task_guids)).all() # type: ignore
|
||||||
human_tasks_to_clear = HumanTaskModel.query.filter(
|
human_tasks_to_clear = HumanTaskModel.query.filter(
|
||||||
HumanTaskModel.task_id.in_(deleted_task_ids) # type: ignore
|
HumanTaskModel.task_id.in_(deleted_task_guids) # type: ignore
|
||||||
).all()
|
).all()
|
||||||
|
|
||||||
# delete human tasks first to avoid potential conflicts when deleting tasks.
|
# delete human tasks first to avoid potential conflicts when deleting tasks.
|
||||||
# otherwise sqlalchemy returns several warnings.
|
# otherwise sqlalchemy returns several warnings.
|
||||||
for task in human_tasks_to_clear + tasks_to_clear:
|
for task in human_tasks_to_clear + tasks_to_clear:
|
||||||
db.session.delete(task)
|
db.session.delete(task)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
bpmn_processes_to_delete = (
|
||||||
|
BpmnProcessModel.query.filter(BpmnProcessModel.guid.in_(deleted_task_guids)) # type: ignore
|
||||||
|
.order_by(BpmnProcessModel.id.desc()) # type: ignore
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
for bpmn_process in bpmn_processes_to_delete:
|
||||||
|
db.session.delete(bpmn_process)
|
||||||
|
|
||||||
# Note: Can't restrict this to definite, because some things are updated and are now CANCELLED
|
# Note: Can't restrict this to definite, because some things are updated and are now CANCELLED
|
||||||
# and other things may have been COMPLETED and are now MAYBE
|
# and other things may have been COMPLETED and are now MAYBE
|
||||||
|
@ -570,6 +581,10 @@ class TaskService:
|
||||||
bpmn_process_identifiers: list[str] = []
|
bpmn_process_identifiers: list[str] = []
|
||||||
if bpmn_process.guid:
|
if bpmn_process.guid:
|
||||||
task_model = TaskModel.query.filter_by(guid=bpmn_process.guid).first()
|
task_model = TaskModel.query.filter_by(guid=bpmn_process.guid).first()
|
||||||
|
if task_model is None:
|
||||||
|
raise TaskNotFoundError(
|
||||||
|
f"Cannot find the corresponding task for the bpmn process with guid {bpmn_process.guid}."
|
||||||
|
)
|
||||||
(
|
(
|
||||||
parent_bpmn_processes,
|
parent_bpmn_processes,
|
||||||
_task_models_of_parent_bpmn_processes,
|
_task_models_of_parent_bpmn_processes,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import Editor from '@monaco-editor/react';
|
import Editor from '@monaco-editor/react';
|
||||||
import {
|
import {
|
||||||
useParams,
|
useParams,
|
||||||
|
@ -40,6 +40,7 @@ import {
|
||||||
import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
|
import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
|
||||||
import { useUriListForPermissions } from '../hooks/UriListForPermissions';
|
import { useUriListForPermissions } from '../hooks/UriListForPermissions';
|
||||||
import {
|
import {
|
||||||
|
ErrorForDisplay,
|
||||||
EventDefinition,
|
EventDefinition,
|
||||||
PermissionsToCheck,
|
PermissionsToCheck,
|
||||||
ProcessData,
|
ProcessData,
|
||||||
|
@ -128,12 +129,18 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
||||||
processInstanceLogListPageBaseUrl = `/admin/logs/${params.process_model_id}/${params.process_instance_id}`;
|
processInstanceLogListPageBaseUrl = `/admin/logs/${params.process_model_id}/${params.process_instance_id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleAddErrorInUseEffect = useCallback((value: ErrorForDisplay) => {
|
||||||
|
addError(value);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!permissionsLoaded) {
|
if (!permissionsLoaded) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const processTaskFailure = () => {
|
const processTaskFailure = (result: any) => {
|
||||||
setTasksCallHadError(true);
|
setTasksCallHadError(true);
|
||||||
|
handleAddErrorInUseEffect(result);
|
||||||
};
|
};
|
||||||
const processTasksSuccess = (results: Task[]) => {
|
const processTasksSuccess = (results: Task[]) => {
|
||||||
if (params.to_task_guid) {
|
if (params.to_task_guid) {
|
||||||
|
@ -190,6 +197,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
||||||
searchParams,
|
searchParams,
|
||||||
taskListPath,
|
taskListPath,
|
||||||
variant,
|
variant,
|
||||||
|
handleAddErrorInUseEffect,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const deleteProcessInstance = () => {
|
const deleteProcessInstance = () => {
|
||||||
|
|
Loading…
Reference in New Issue