From 03b961b53f4cd0ffa0d2610d86141119f99830ac Mon Sep 17 00:00:00 2001 From: mike cullerton Date: Mon, 9 Jan 2023 13:00:51 -0500 Subject: [PATCH 01/17] Add `fault_or_suspend_on_exception` and `exception_notification_addresses` to Process Model interface and create/update form. --- .../src/components/ProcessModelForm.tsx | 115 ++++++++++++++++++ spiffworkflow-frontend/src/interfaces.ts | 2 + 2 files changed, 117 insertions(+) diff --git a/spiffworkflow-frontend/src/components/ProcessModelForm.tsx b/spiffworkflow-frontend/src/components/ProcessModelForm.tsx index 7cfd4d616..84a01987a 100644 --- a/spiffworkflow-frontend/src/components/ProcessModelForm.tsx +++ b/spiffworkflow-frontend/src/components/ProcessModelForm.tsx @@ -8,6 +8,8 @@ import { TextInput, Grid, Column, + Select, + SelectItem, // @ts-ignore } from '@carbon/react'; // @ts-ignore @@ -76,6 +78,8 @@ export default function ProcessModelForm({ display_name: processModel.display_name, description: processModel.description, metadata_extraction_paths: processModel.metadata_extraction_paths, + fault_or_suspend_on_exception: processModel.fault_or_suspend_on_exception, + exception_notification_addresses: processModel.exception_notification_addresses, }; if (mode === 'new') { Object.assign(postBody, { @@ -173,6 +177,69 @@ export default function ProcessModelForm({ updateProcessModel({ metadata_extraction_paths: cep }); }; + const notificationAddressForm = ( + index: number, + notificationAddress: string + ) => { + return ( + + + { + const notificationAddresses: string[] = + processModel.exception_notification_addresses || []; + notificationAddresses[index] = event.target.value; + updateProcessModel({ + exception_notification_addresses: notificationAddresses, + }); + }} + /> + + + + + + ); + textInputs.push(

Metadata Extractions

); textInputs.push( diff --git a/spiffworkflow-frontend/src/interfaces.ts b/spiffworkflow-frontend/src/interfaces.ts index 97ef763c1..9d3d17ccd 100644 --- a/spiffworkflow-frontend/src/interfaces.ts +++ b/spiffworkflow-frontend/src/interfaces.ts @@ -146,6 +146,8 @@ export interface ProcessModel { files: ProcessFile[]; parent_groups?: ProcessGroupLite[]; metadata_extraction_paths?: MetadataExtractionPath[]; + fault_or_suspend_on_exception?: string; + exception_notification_addresses?: string[]; } export interface ProcessGroup { From e62cdad588406537684cb6b7f087e4d3f55981dd Mon Sep 17 00:00:00 2001 From: mike cullerton Date: Mon, 9 Jan 2023 13:02:34 -0500 Subject: [PATCH 02/17] Update process_models_controller to include `fault_or_suspend_on_exception` and `exception_notification_addresses` for Process Model create/update --- .../spiffworkflow_backend/routes/process_models_controller.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_models_controller.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_models_controller.py index 1709357a7..f50089dc5 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_models_controller.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_models_controller.py @@ -49,6 +49,8 @@ def process_model_create( "primary_process_id", "description", "metadata_extraction_paths", + "fault_or_suspend_on_exception", + "exception_notification_addresses", ] body_filtered = { include_item: body[include_item] @@ -100,6 +102,8 @@ def process_model_update( "primary_process_id", "description", "metadata_extraction_paths", + "fault_or_suspend_on_exception", + "exception_notification_addresses", ] body_filtered = { include_item: body[include_item] From 61699b6b5d643b91dae0396958f986b2abec067a Mon Sep 17 00:00:00 2001 From: mike cullerton Date: Tue, 10 Jan 2023 08:44:53 -0500 Subject: [PATCH 03/17] Work on System Notification handler --- .../spiffworkflow_backend/config/default.py | 3 + .../services/error_handling_service.py | 123 ++++++++++++------ 2 files changed, 86 insertions(+), 40 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py b/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py index d0d6a4010..1a2f7504a 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py @@ -74,3 +74,6 @@ SPIFF_DATABASE_TYPE = environ.get( SPIFFWORKFLOW_BACKEND_DATABASE_URI = environ.get( "SPIFFWORKFLOW_BACKEND_DATABASE_URI", default=None ) +SYSTEM_NOTIFICATION_PROCESS_MODEL_MESSAGE_ID = environ.get( + "SYSTEM_NOTIFICATION_PROCESS_MODEL_MESSAGE_ID", default="Message_SystemMessageNotification" +) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py index 1e8b38f2d..1c8e66a33 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py @@ -1,4 +1,9 @@ """Error_handling_service.""" +import json + +from flask import g +from flask import current_app +from flask.wrappers import Response from typing import Any from typing import List from typing import Union @@ -6,9 +11,15 @@ from typing import Union from flask_bpmn.api.api_error import ApiError from flask_bpmn.models.db import db +from spiffworkflow_backend.models.message_model import MessageModel +from spiffworkflow_backend.models.message_triggerable_process_model import ( + MessageTriggerableProcessModel, +) from spiffworkflow_backend.models.process_instance import ProcessInstanceModel +from spiffworkflow_backend.models.process_instance import ProcessInstanceModelSchema from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus from spiffworkflow_backend.services.email_service import EmailService +from spiffworkflow_backend.services.message_service import MessageService from spiffworkflow_backend.services.process_instance_processor import ( ProcessInstanceProcessor, ) @@ -37,6 +48,7 @@ class ErrorHandlingService: process_model = ProcessModelService.get_process_model( _processor.process_model_identifier ) + # First, suspend or fault the instance if process_model.fault_or_suspend_on_exception == "suspend": self.set_instance_status( _processor.process_instance_model.id, @@ -49,57 +61,88 @@ class ErrorHandlingService: ProcessInstanceStatus.error.value, ) + # Second, call the System Notification Process + # Note that this isn't the best way to do this. + # The configs are all in the model. + # Maybe we can move some of this to the notification process, or dmn tables. if len(process_model.exception_notification_addresses) > 0: try: - # some notification method (waku?) - self.handle_email_notification( - _processor, _error, process_model.exception_notification_addresses - ) + self.handle_system_notification(_error, process_model.exception_notification_addresses) except Exception as e: # hmm... what to do if a notification method fails. Probably log, at least print(e) @staticmethod - def hanle_sentry_notification(_error: ApiError, _recipients: List) -> None: - """SentryHandler.""" - ... - - @staticmethod - def handle_email_notification( - processor: ProcessInstanceProcessor, + def handle_system_notification( error: Union[ApiError, Exception], recipients: List, - ) -> None: - """EmailHandler.""" - subject = "Unexpected error in app" - if isinstance(error, ApiError): - content = f"{error.message}" - else: - content = str(error) - content_html = content - - EmailService.add_email( - subject, - "sender@company.com", - recipients, - content, - content_html, - cc=None, - bcc=None, - reply_to=None, - attachment_files=None, + ): + message_payload = { + 'my_var': 'my_value', + 'error': error.__repr__(), + 'recipients': recipients + } + message_identifier = current_app.config["SYSTEM_NOTIFICATION_PROCESS_MODEL_MESSAGE_ID"] + message_model = MessageModel.query.filter_by(identifier=message_identifier).first() + message_triggerable_process_model = ( + MessageTriggerableProcessModel.query.filter_by( + message_model_id=message_model.id + ).first() + ) + process_instance = MessageService.process_message_triggerable_process_model( + message_triggerable_process_model, + message_identifier, + message_payload, + g.user ) - @staticmethod - def handle_waku_notification(_error: ApiError, _recipients: List) -> Any: - """WakuHandler.""" - # class WakuMessage: - # """WakuMessage.""" - # - # payload: str - # contentTopic: str # Optional - # version: int # Optional - # timestamp: int # Optional + return Response( + json.dumps(ProcessInstanceModelSchema().dump(process_instance)), + status=200, + mimetype="application/json", + ) + + # @staticmethod + # def handle_sentry_notification(_error: ApiError, _recipients: List) -> None: + # """SentryHandler.""" + # ... + # + # @staticmethod + # def handle_email_notification( + # processor: ProcessInstanceProcessor, + # error: Union[ApiError, Exception], + # recipients: List, + # ) -> None: + # """EmailHandler.""" + # subject = "Unexpected error in app" + # if isinstance(error, ApiError): + # content = f"{error.message}" + # else: + # content = str(error) + # content_html = content + # + # EmailService.add_email( + # subject, + # "sender@company.com", + # recipients, + # content, + # content_html, + # cc=None, + # bcc=None, + # reply_to=None, + # attachment_files=None, + # ) + # + # @staticmethod + # def handle_waku_notification(_error: ApiError, _recipients: List) -> Any: + # """WakuHandler.""" + # # class WakuMessage: + # # """WakuMessage.""" + # # + # # payload: str + # # contentTopic: str # Optional + # # version: int # Optional + # # timestamp: int # Optional class FailingService: From 505964c88085416db5005a8d8e400f05c22da57d Mon Sep 17 00:00:00 2001 From: mike cullerton Date: Tue, 10 Jan 2023 16:33:51 -0500 Subject: [PATCH 04/17] Removed test for email error handler. Added stub for testing system handler process --- .../integration/test_process_api.py | 57 ++----------------- 1 file changed, 4 insertions(+), 53 deletions(-) diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py index f52480505..efc22ab54 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py @@ -2160,59 +2160,10 @@ class TestProcessApi(BaseTest): assert process is not None assert process.status == "suspended" - def test_error_handler_with_email( - self, - app: Flask, - client: FlaskClient, - with_db_and_bpmn_file_cleanup: None, - with_super_admin_user: UserModel, - ) -> None: - """Test_error_handler.""" - process_group_id = "data" - process_model_id = "error" - bpmn_file_name = "error.bpmn" - bpmn_file_location = "error" - process_model_identifier = self.create_group_and_model_with_bpmn( - client, - with_super_admin_user, - process_group_id=process_group_id, - process_model_id=process_model_id, - bpmn_file_name=bpmn_file_name, - bpmn_file_location=bpmn_file_location, - ) - - process_instance_id = self.setup_testing_instance( - client, process_model_identifier, with_super_admin_user - ) - - process_model = ProcessModelService.get_process_model(process_model_identifier) - ProcessModelService.update_process_model( - process_model, - {"exception_notification_addresses": ["with_super_admin_user@example.com"]}, - ) - - mail = app.config["MAIL_APP"] - with mail.record_messages() as outbox: - response = client.post( - f"/v1.0/process-instances/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}/run", - headers=self.logged_in_headers(with_super_admin_user), - ) - assert response.status_code == 400 - assert len(outbox) == 1 - message = outbox[0] - assert message.subject == "Unexpected error in app" - assert ( - message.body == 'TypeError:can only concatenate str (not "int") to str' - ) - assert message.recipients == process_model.exception_notification_addresses - - process = ( - db.session.query(ProcessInstanceModel) - .filter(ProcessInstanceModel.id == process_instance_id) - .first() - ) - assert process is not None - assert process.status == "error" + def test_error_handler_system_notification(self): + """Test_error_handler_system_notification.""" + # TODO: make sure the system notification process is run on exceptions + ... def test_task_data_is_set_even_if_process_instance_errors( self, From 95141a68327f53cbd778775f322e5ca572177486 Mon Sep 17 00:00:00 2001 From: mike cullerton Date: Wed, 11 Jan 2023 17:46:39 -0500 Subject: [PATCH 05/17] mypy --- .../spiffworkflow_backend/services/error_handling_service.py | 2 +- .../tests/spiffworkflow_backend/integration/test_process_api.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py index 1c8e66a33..5d6346d77 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py @@ -76,7 +76,7 @@ class ErrorHandlingService: def handle_system_notification( error: Union[ApiError, Exception], recipients: List, - ): + ) -> Response: message_payload = { 'my_var': 'my_value', 'error': error.__repr__(), diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py index efc22ab54..d4e630f36 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py @@ -2160,7 +2160,7 @@ class TestProcessApi(BaseTest): assert process is not None assert process.status == "suspended" - def test_error_handler_system_notification(self): + def test_error_handler_system_notification(self) -> None: """Test_error_handler_system_notification.""" # TODO: make sure the system notification process is run on exceptions ... From 1440a91efb76b19ec67aaa705f98c24a0a7e0700 Mon Sep 17 00:00:00 2001 From: mike cullerton Date: Wed, 11 Jan 2023 17:47:58 -0500 Subject: [PATCH 06/17] linting --- spiffworkflow-frontend/src/components/ProcessModelForm.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spiffworkflow-frontend/src/components/ProcessModelForm.tsx b/spiffworkflow-frontend/src/components/ProcessModelForm.tsx index 84a01987a..999356952 100644 --- a/spiffworkflow-frontend/src/components/ProcessModelForm.tsx +++ b/spiffworkflow-frontend/src/components/ProcessModelForm.tsx @@ -79,7 +79,8 @@ export default function ProcessModelForm({ description: processModel.description, metadata_extraction_paths: processModel.metadata_extraction_paths, fault_or_suspend_on_exception: processModel.fault_or_suspend_on_exception, - exception_notification_addresses: processModel.exception_notification_addresses, + exception_notification_addresses: + processModel.exception_notification_addresses, }; if (mode === 'new') { Object.assign(postBody, { From 6e3a79320ebec51c7b78c0000f7dbfd0dde18ff9 Mon Sep 17 00:00:00 2001 From: mike cullerton Date: Wed, 11 Jan 2023 18:12:18 -0500 Subject: [PATCH 07/17] Precommit --- .../spiffworkflow_backend/services/error_handling_service.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py index 5d6346d77..b700e7813 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py @@ -4,7 +4,7 @@ import json from flask import g from flask import current_app from flask.wrappers import Response -from typing import Any +# from typing import Any from typing import List from typing import Union @@ -18,7 +18,7 @@ from spiffworkflow_backend.models.message_triggerable_process_model import ( from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.process_instance import ProcessInstanceModelSchema from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus -from spiffworkflow_backend.services.email_service import EmailService +# from spiffworkflow_backend.services.email_service import EmailService from spiffworkflow_backend.services.message_service import MessageService from spiffworkflow_backend.services.process_instance_processor import ( ProcessInstanceProcessor, @@ -77,6 +77,7 @@ class ErrorHandlingService: error: Union[ApiError, Exception], recipients: List, ) -> Response: + """Handle_system_notification.""" message_payload = { 'my_var': 'my_value', 'error': error.__repr__(), From b6cd66cb93a01c1d1f1c391a86262014d8d34874 Mon Sep 17 00:00:00 2001 From: mike cullerton Date: Thu, 12 Jan 2023 07:13:35 -0500 Subject: [PATCH 08/17] Cleaned up the message text --- .../services/error_handling_service.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py index b700e7813..4b203e34f 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py @@ -18,6 +18,7 @@ from spiffworkflow_backend.models.message_triggerable_process_model import ( from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.process_instance import ProcessInstanceModelSchema from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus +from spiffworkflow_backend.models.process_model import ProcessModelInfo # from spiffworkflow_backend.services.email_service import EmailService from spiffworkflow_backend.services.message_service import MessageService from spiffworkflow_backend.services.process_instance_processor import ( @@ -67,7 +68,7 @@ class ErrorHandlingService: # Maybe we can move some of this to the notification process, or dmn tables. if len(process_model.exception_notification_addresses) > 0: try: - self.handle_system_notification(_error, process_model.exception_notification_addresses) + self.handle_system_notification(_error, process_model) except Exception as e: # hmm... what to do if a notification method fails. Probably log, at least print(e) @@ -75,12 +76,13 @@ class ErrorHandlingService: @staticmethod def handle_system_notification( error: Union[ApiError, Exception], - recipients: List, + process_model: ProcessModelInfo ) -> Response: """Handle_system_notification.""" + recipients = process_model.exception_notification_addresses + message_text = f"There was an exception running process {process_model.id}.\nOriginal Error:\n{error.__repr__()}" message_payload = { - 'my_var': 'my_value', - 'error': error.__repr__(), + 'message_text': message_text, 'recipients': recipients } message_identifier = current_app.config["SYSTEM_NOTIFICATION_PROCESS_MODEL_MESSAGE_ID"] From b6777ae65cba96e9a2a813a2d3cadf72029da4f6 Mon Sep 17 00:00:00 2001 From: Jon Herron Date: Thu, 12 Jan 2023 18:16:06 -0500 Subject: [PATCH 09/17] POC checking cumulative task data len --- .../services/process_instance_processor.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 3631f0b79..5dddcbbd8 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -564,10 +564,25 @@ class ProcessInstanceProcessor: "lane_assignment_id": lane_assignment_id, } + def check_task_data_size(self, tasks_dict: dict) -> None: + """CheckTaskDataSize.""" + task_data = [v["data"] for v in tasks_dict.values() if len(v["data"]) > 0] + task_data_len = len(json.dumps(task_data)) + task_data_limit = 1024 + + if task_data_len > task_data_limit: + raise ( + ApiError( + error_code="task_data_size_exceeded", + message=f"Maximum task data size of {task_data_limit} exceeded." + ) + ) + def spiff_step_details_mapping(self) -> dict: """SaveSpiffStepDetails.""" bpmn_json = self.serialize() wf_json = json.loads(bpmn_json) + self.check_task_data_size(wf_json["tasks"]) task_json = {"tasks": wf_json["tasks"], "subprocesses": wf_json["subprocesses"]} return { From 1b413c5f9e22e67ac265fbeb11f26e0235ce7b53 Mon Sep 17 00:00:00 2001 From: mike cullerton Date: Fri, 13 Jan 2023 08:40:56 -0500 Subject: [PATCH 10/17] unused imports --- .../spiffworkflow_backend/services/error_handling_service.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py index f655ff731..e2c93b5d0 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py @@ -2,10 +2,7 @@ import json from flask import g -from flask import current_app from flask.wrappers import Response -# from typing import Any -from typing import List from typing import Union from flask import current_app @@ -20,7 +17,6 @@ from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.process_instance import ProcessInstanceModelSchema from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus from spiffworkflow_backend.models.process_model import ProcessModelInfo -# from spiffworkflow_backend.services.email_service import EmailService from spiffworkflow_backend.services.message_service import MessageService from spiffworkflow_backend.services.process_instance_processor import ( ProcessInstanceProcessor, From d59df48e0cb61fabf8185e73c81237cd5929ec8e Mon Sep 17 00:00:00 2001 From: mike cullerton Date: Fri, 13 Jan 2023 08:52:43 -0500 Subject: [PATCH 11/17] import order --- .../services/error_handling_service.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py index e2c93b5d0..f5119b838 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py @@ -2,10 +2,9 @@ import json from flask import g -from flask.wrappers import Response -from typing import Union - from flask import current_app +from flask.wrappers import Response + from flask_bpmn.api.api_error import ApiError from flask_bpmn.models.db import db @@ -23,6 +22,8 @@ from spiffworkflow_backend.services.process_instance_processor import ( ) from spiffworkflow_backend.services.process_model_service import ProcessModelService +from typing import Union + class ErrorHandlingService: """ErrorHandlingService.""" From 001db4cd847a976af36c3ae36134ddad1df1670f Mon Sep 17 00:00:00 2001 From: mike cullerton Date: Fri, 13 Jan 2023 09:03:17 -0500 Subject: [PATCH 12/17] reorder imports --- .../services/error_handling_service.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py index f5119b838..a161f2517 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py @@ -1,13 +1,12 @@ """Error_handling_service.""" import json +from typing import Union -from flask import g from flask import current_app +from flask import g from flask.wrappers import Response - from flask_bpmn.api.api_error import ApiError from flask_bpmn.models.db import db - from spiffworkflow_backend.models.message_model import MessageModel from spiffworkflow_backend.models.message_triggerable_process_model import ( MessageTriggerableProcessModel, @@ -22,8 +21,6 @@ from spiffworkflow_backend.services.process_instance_processor import ( ) from spiffworkflow_backend.services.process_model_service import ProcessModelService -from typing import Union - class ErrorHandlingService: """ErrorHandlingService.""" From 3cb02914ef858cba3c58e7deb50ed7d5511d0222 Mon Sep 17 00:00:00 2001 From: Jon Herron Date: Fri, 13 Jan 2023 09:05:35 -0500 Subject: [PATCH 13/17] Better impl --- .../services/process_instance_processor.py | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 5dddcbbd8..5de0d4ac7 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -564,25 +564,10 @@ class ProcessInstanceProcessor: "lane_assignment_id": lane_assignment_id, } - def check_task_data_size(self, tasks_dict: dict) -> None: - """CheckTaskDataSize.""" - task_data = [v["data"] for v in tasks_dict.values() if len(v["data"]) > 0] - task_data_len = len(json.dumps(task_data)) - task_data_limit = 1024 - - if task_data_len > task_data_limit: - raise ( - ApiError( - error_code="task_data_size_exceeded", - message=f"Maximum task data size of {task_data_limit} exceeded." - ) - ) - def spiff_step_details_mapping(self) -> dict: """SaveSpiffStepDetails.""" bpmn_json = self.serialize() wf_json = json.loads(bpmn_json) - self.check_task_data_size(wf_json["tasks"]) task_json = {"tasks": wf_json["tasks"], "subprocesses": wf_json["subprocesses"]} return { @@ -1283,8 +1268,33 @@ class ProcessInstanceProcessor: except WorkflowTaskExecException as we: raise ApiError.from_workflow_exception("task_error", str(we), we) from we + def user_defined_task_data(self, task_data: dict) -> dict: + """UserDefinedTaskData.""" + return {k: v for k, v in task_data.items() if k != "current_user"} + + def check_task_data_size(self) -> None: + """CheckTaskDataSize.""" + tasks_to_check = self.bpmn_process_instance.get_tasks(TaskState.FINISHED_MASK) + task_data = [self.user_defined_task_data(task.data) for task in tasks_to_check] + task_data_to_check = list(filter(len, task_data)) + + if len(task_data_to_check) == 0: + return + + task_data_len = len(json.dumps(task_data_to_check)) + task_data_limit = 1024 + + if task_data_len > task_data_limit: + raise ( + ApiError( + error_code="task_data_size_exceeded", + message=f"Maximum task data size of {task_data_limit} exceeded." + ) + ) + def serialize(self) -> str: """Serialize.""" + self.check_task_data_size() return self._serializer.serialize_json(self.bpmn_process_instance) # type: ignore def next_user_tasks(self) -> list[SpiffTask]: From 5b5c6e0265c11330178b04351ee7c6b8f54f0445 Mon Sep 17 00:00:00 2001 From: Jon Herron Date: Fri, 13 Jan 2023 09:12:41 -0500 Subject: [PATCH 14/17] Bump the limit to 1mb --- .../services/process_instance_processor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 5de0d4ac7..f8e1f3d37 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -1282,7 +1282,7 @@ class ProcessInstanceProcessor: return task_data_len = len(json.dumps(task_data_to_check)) - task_data_limit = 1024 + task_data_limit = 1024**2 if task_data_len > task_data_limit: raise ( From b9337437176605cf8ad633aeff46ea5ded800aa6 Mon Sep 17 00:00:00 2001 From: Jon Herron Date: Fri, 13 Jan 2023 09:45:05 -0500 Subject: [PATCH 15/17] Getting ./bin/pyl to pass --- .../services/process_instance_processor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index f8e1f3d37..135fbf144 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -1288,7 +1288,7 @@ class ProcessInstanceProcessor: raise ( ApiError( error_code="task_data_size_exceeded", - message=f"Maximum task data size of {task_data_limit} exceeded." + message=f"Maximum task data size of {task_data_limit} exceeded.", ) ) From 91a0f05b118747f51449350e35edcea9539889c6 Mon Sep 17 00:00:00 2001 From: Jon Herron Date: Fri, 13 Jan 2023 11:11:12 -0500 Subject: [PATCH 16/17] Fixed failing test --- .../services/process_instance_processor.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 135fbf144..bf8c42b50 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -1278,10 +1278,11 @@ class ProcessInstanceProcessor: task_data = [self.user_defined_task_data(task.data) for task in tasks_to_check] task_data_to_check = list(filter(len, task_data)) - if len(task_data_to_check) == 0: - return + try: + task_data_len = len(json.dumps(task_data_to_check)) + except Exception: + task_data_len = 0 - task_data_len = len(json.dumps(task_data_to_check)) task_data_limit = 1024**2 if task_data_len > task_data_limit: From c3e1dda51e70fab11192ea74e8abe18aed716cba Mon Sep 17 00:00:00 2001 From: mike cullerton Date: Fri, 13 Jan 2023 11:50:36 -0500 Subject: [PATCH 17/17] run_pyl changes --- .../spiffworkflow_backend/config/default.py | 3 ++- .../services/error_handling_service.py | 24 +++++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py b/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py index 431947fce..80cfb9191 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/config/default.py @@ -78,5 +78,6 @@ SPIFFWORKFLOW_BACKEND_DATABASE_URI = environ.get( "SPIFFWORKFLOW_BACKEND_DATABASE_URI", default=None ) SYSTEM_NOTIFICATION_PROCESS_MODEL_MESSAGE_ID = environ.get( - "SYSTEM_NOTIFICATION_PROCESS_MODEL_MESSAGE_ID", default="Message_SystemMessageNotification" + "SYSTEM_NOTIFICATION_PROCESS_MODEL_MESSAGE_ID", + default="Message_SystemMessageNotification", ) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py index a161f2517..51f402fac 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/error_handling_service.py @@ -7,6 +7,7 @@ from flask import g from flask.wrappers import Response from flask_bpmn.api.api_error import ApiError from flask_bpmn.models.db import db + from spiffworkflow_backend.models.message_model import MessageModel from spiffworkflow_backend.models.message_triggerable_process_model import ( MessageTriggerableProcessModel, @@ -70,18 +71,21 @@ class ErrorHandlingService: @staticmethod def handle_system_notification( - error: Union[ApiError, Exception], - process_model: ProcessModelInfo + error: Union[ApiError, Exception], process_model: ProcessModelInfo ) -> Response: """Handle_system_notification.""" recipients = process_model.exception_notification_addresses - message_text = f"There was an exception running process {process_model.id}.\nOriginal Error:\n{error.__repr__()}" - message_payload = { - 'message_text': message_text, - 'recipients': recipients - } - message_identifier = current_app.config["SYSTEM_NOTIFICATION_PROCESS_MODEL_MESSAGE_ID"] - message_model = MessageModel.query.filter_by(identifier=message_identifier).first() + message_text = ( + f"There was an exception running process {process_model.id}.\nOriginal" + f" Error:\n{error.__repr__()}" + ) + message_payload = {"message_text": message_text, "recipients": recipients} + message_identifier = current_app.config[ + "SYSTEM_NOTIFICATION_PROCESS_MODEL_MESSAGE_ID" + ] + message_model = MessageModel.query.filter_by( + identifier=message_identifier + ).first() message_triggerable_process_model = ( MessageTriggerableProcessModel.query.filter_by( message_model_id=message_model.id @@ -91,7 +95,7 @@ class ErrorHandlingService: message_triggerable_process_model, message_identifier, message_payload, - g.user + g.user, ) return Response(