Merge pull request #340 from sartography/bug/better_errors_on_scheduled_tasks

Assure we log reasonably clear errors when executing scheduled tasks …
This commit is contained in:
Mike Cullerton 2021-07-12 10:13:02 -04:00 committed by GitHub
commit 522ca9d164
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 105 additions and 10 deletions

View File

@ -9,7 +9,7 @@ class GetStudyAssociates(Script):
def get_description(self):
return """
Returns person assocated with study or an error if one is not associated.
Returns people associated with a study or an error if one is not associated.
example : get_study_associate('sbp3ey') => {'uid':'sbp3ey','role':'Unicorn Herder', 'send_email': False,
'access':True}

View File

@ -14,12 +14,12 @@ from crc import db, session, app
from crc.api.common import ApiError
from crc.models.data_store import DataStoreModel
from crc.models.email import EmailModel
from crc.models.file import FileDataModel, FileModel, FileModelSchema, File, LookupFileModel, LookupDataModel
from crc.models.file import FileModel, File
from crc.models.ldap import LdapSchema
from crc.models.protocol_builder import ProtocolBuilderStudy, ProtocolBuilderStatus
from crc.models.study import StudyModel, Study, StudyStatus, Category, WorkflowMetadata, StudyEventType, StudyEvent, \
IrbStatus, StudyAssociated
from crc.models.task_event import TaskEventModel, TaskEvent
from crc.models.protocol_builder import ProtocolBuilderStudy
from crc.models.study import StudyModel, Study, StudyStatus, Category, \
WorkflowMetadata, StudyEventType, StudyEvent, IrbStatus, StudyAssociated
from crc.models.task_event import TaskEventModel
from crc.models.workflow import WorkflowSpecCategoryModel, WorkflowModel, WorkflowSpecModel, WorkflowState, \
WorkflowStatus, WorkflowSpecDependencyFile
from crc.services.document_service import DocumentService

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], f"workflow #%i" % workflow.id)
self.assertRegexpMatches(cm.output[0], f"study #%i" % workflow.study_id)
self.assertTrue(wf.status == WorkflowStatus.waiting)