attempt to save again if deadlock given for draft data save w/ burnettk (#410)

Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
jasquat 2023-07-26 11:08:17 -04:00 committed by GitHub
parent 58cc0d9c14
commit 148bf386e3
2 changed files with 35 additions and 20 deletions

View File

@ -14,6 +14,7 @@ from flask import jsonify
from flask import make_response
from flask import stream_with_context
from flask.wrappers import Response
from MySQLdb import OperationalError # type: ignore
from SpiffWorkflow.bpmn.exceptions import WorkflowTaskException # type: ignore
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow # type: ignore
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
@ -586,13 +587,21 @@ def task_save_draft(
principal = _find_principal_or_raise()
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
if not process_instance.can_submit_task():
raise ApiError(
error_code="process_instance_not_runnable",
message=(
f"Process Instance ({process_instance.id}) has status "
f"{process_instance.status} which does not allow draft data to be saved."
return Response(
json.dumps(
{
"ok": True,
"saved": False,
"message": (
f"Process Instance ({process_instance.id}) has status "
f"{process_instance.status} which does not allow draft data to be saved."
),
"process_model_identifier": process_instance.process_model_identifier,
"process_instance_id": process_instance_id,
}
),
status_code=400,
status=200,
mimetype="application/json",
)
try:
@ -610,12 +619,30 @@ def task_save_draft(
if json_data_dict is not None:
JsonDataModel.insert_or_update_json_data_dict(json_data_dict)
db.session.add(task_draft_data)
db.session.commit()
try:
db.session.commit()
except OperationalError as exception:
db.session.rollback()
if "Deadlock" in str(exception):
task_draft_data = TaskService.task_draft_data_from_task_model(task_model)
# if we do not find a task_draft_data record, that means it was deleted when the form was submitted
# and we therefore have no need to save draft data
if task_draft_data is not None:
json_data_dict = TaskService.update_task_data_on_task_model_and_return_dict_if_updated(
task_draft_data, body, "saved_form_data_hash"
)
if json_data_dict is not None:
JsonDataModel.insert_or_update_json_data_dict(json_data_dict)
db.session.add(task_draft_data)
db.session.commit()
else:
raise exception
return Response(
json.dumps(
{
"ok": True,
"saved": True,
"process_model_identifier": process_instance.process_model_identifier,
"process_instance_id": process_instance_id,
}

View File

@ -21,7 +21,7 @@ import {
modifyProcessIdentifierForPathParam,
recursivelyChangeNullAndUndefined,
} from '../helpers';
import { ErrorForDisplay, EventDefinition, Task } from '../interfaces';
import { EventDefinition, Task } from '../interfaces';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
import InstructionsForEndUser from '../components/InstructionsForEndUser';
import TypeaheadWidget from '../rjsf/custom_widgets/TypeaheadWidget/TypeaheadWidget';
@ -77,17 +77,6 @@ export default function TaskShow() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [params]);
const handleAutoSaveError = (error: ErrorForDisplay) => {
if (
error.error_code &&
error.error_code === 'process_instance_not_runnable'
) {
return undefined;
}
addError(error);
return undefined;
};
// Before we auto-saved form data, we remembered what data was in the form, and then created a synthetic submit event
// in order to implement a "Save and close" button. That button no longer saves (since we have auto-save), but the crazy
// frontend code to support that Save and close button is here, in case we need to reference that someday:
@ -106,7 +95,6 @@ export default function TaskShow() {
postBody: formData,
httpMethod: 'POST',
successCallback: successCallbackToUse,
failureCallback: handleAutoSaveError,
});
return undefined;
};