Assure we log reasonably clear errors when executing scheduled tasks in the background, so that sentry can pick them up and they can be addressed effectively.

This commit is contained in:
Dan 2021-07-12 09:43:12 -04:00
parent bef35e4bec
commit 1916c4ff54
3 changed files with 99 additions and 4 deletions

View File

@ -98,15 +98,18 @@ class WorkflowService(object):
def do_waiting():
records = db.session.query(WorkflowModel).filter(WorkflowModel.status==WorkflowStatus.waiting).all()
for workflow_model in records:
# fixme: Try catch with a very explicit error about the study, workflow and task that failed.
try:
app.logger.info('Processing workflow %s' % workflow_model.id)
processor = WorkflowProcessor(workflow_model)
processor.bpmn_workflow.refresh_waiting_tasks()
processor.bpmn_workflow.do_engine_steps()
processor.save()
except:
app.logger.error('Failed to process workflow')
except Exception as e:
app.logger.error(f"Error running waiting task for workflow #%i (%s) for study #%i. %s" %
(workflow_model.id,
workflow_model.workflow_spec.name,
workflow_model.study_id,
str(e)))
@staticmethod
@timeit

View File

@ -0,0 +1,76 @@
<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_0ilr8m3" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.7.3">
<bpmn:process id="timer" isExecutable="true">
<bpmn:startEvent id="StartEvent_1">
<bpmn:outgoing>Flow_1pahvlr</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:manualTask id="get_coffee" name="Eat Spam">
<bpmn:incoming>Flow_1pahvlr</bpmn:incoming>
<bpmn:outgoing>Flow_1pvkgnu</bpmn:outgoing>
</bpmn:manualTask>
<bpmn:manualTask id="back_to_work" name="Get Back To Work">
<bpmn:incoming>Flow_1pvkgnu</bpmn:incoming>
<bpmn:outgoing>Flow_1ekgt3x</bpmn:outgoing>
</bpmn:manualTask>
<bpmn:endEvent id="Event_03w65sk">
<bpmn:incoming>Flow_1ekgt3x</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_1ekgt3x" sourceRef="back_to_work" targetRef="Event_03w65sk" />
<bpmn:sequenceFlow id="Flow_1pvkgnu" sourceRef="get_coffee" targetRef="back_to_work" />
<bpmn:sequenceFlow id="Flow_1pahvlr" sourceRef="StartEvent_1" targetRef="get_coffee" />
<bpmn:sequenceFlow id="Flow_05lcpdf" sourceRef="Event_1txv76c" targetRef="Activity_0onlql2" />
<bpmn:scriptTask id="Activity_0onlql2" name="Do Bad Burp">
<bpmn:incoming>Flow_05lcpdf</bpmn:incoming>
<bpmn:script># Tries to burp, failes.
my_burp = non_existent_burp_variable</bpmn:script>
</bpmn:scriptTask>
<bpmn:boundaryEvent id="Event_1txv76c" name="burp?" attachedToRef="get_coffee">
<bpmn:outgoing>Flow_05lcpdf</bpmn:outgoing>
<bpmn:timerEventDefinition id="TimerEventDefinition_1rvot87">
<bpmn:timeDuration xsi:type="bpmn:tFormalExpression">timedelta(seconds=.25)</bpmn:timeDuration>
</bpmn:timerEventDefinition>
</bpmn:boundaryEvent>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="timer">
<bpmndi:BPMNEdge id="Flow_1pahvlr_di" bpmnElement="Flow_1pahvlr">
<di:waypoint x="215" y="117" />
<di:waypoint x="260" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1pvkgnu_di" bpmnElement="Flow_1pvkgnu">
<di:waypoint x="360" y="117" />
<di:waypoint x="533" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1ekgt3x_di" bpmnElement="Flow_1ekgt3x">
<di:waypoint x="633" y="117" />
<di:waypoint x="682" y="117" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_05lcpdf_di" bpmnElement="Flow_05lcpdf">
<di:waypoint x="300" y="175" />
<di:waypoint x="300" y="180" />
<di:waypoint x="380" y="180" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds x="179" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_0tjl9dd_di" bpmnElement="get_coffee">
<dc:Bounds x="260" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_15zi5m4_di" bpmnElement="back_to_work">
<dc:Bounds x="533" y="77" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_03w65sk_di" bpmnElement="Event_03w65sk">
<dc:Bounds x="682" y="99" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_05taua6_di" bpmnElement="Activity_0onlql2">
<dc:Bounds x="380" y="140" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_0xco4d9_di" bpmnElement="Event_1txv76c">
<dc:Bounds x="282" y="139" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="286" y="182" width="29" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -1,13 +1,13 @@
import json
import time
from crc.services.workflow_processor import WorkflowProcessor
from tests.base_test import BaseTest
from crc.models.workflow import WorkflowStatus, WorkflowModel
from crc import db
from crc.api.common import ApiError
from crc.models.task_event import TaskEventModel, TaskEventSchema
from crc.services.workflow_service import WorkflowService
from crc.services.workflow_processor import WorkflowProcessor
class TestTimerEvent(BaseTest):
@ -28,3 +28,19 @@ class TestTimerEvent(BaseTest):
wf = db.session.query(WorkflowModel).filter(WorkflowModel.id == workflow.id).first()
self.assertTrue(wf.status != WorkflowStatus.waiting)
def test_waiting_event_error(self):
workflow = self.create_workflow('timer_event_error')
processor = WorkflowProcessor(workflow)
processor.do_engine_steps()
processor.save()
time.sleep(.3) # our timer is at .25 sec so we have to wait for it
# get done waiting
wf = db.session.query(WorkflowModel).filter(WorkflowModel.id == workflow.id).first()
self.assertTrue(wf.status == WorkflowStatus.waiting)
with self.assertLogs('crc', level='ERROR') as cm:
WorkflowService.do_waiting()
self.assertEqual(1, len(cm.output))
self.assertRegexpMatches(cm.output[0], "workflow #1")
self.assertRegexpMatches(cm.output[0], "study #1")
self.assertTrue(wf.status == WorkflowStatus.waiting)