Optimistically skip some timers (#232)
This commit is contained in:
parent
e9827d0d5e
commit
ed3c0d7766
|
@ -2,7 +2,10 @@
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import time
|
import time
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timezone
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
from typing import Dict
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
@ -12,6 +15,7 @@ from urllib.parse import unquote
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from flask import g
|
from flask import g
|
||||||
|
from SpiffWorkflow.bpmn.specs.events.event_definitions import TimerEventDefinition # type: ignore
|
||||||
from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import _BoundaryEventParent # type: ignore
|
from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import _BoundaryEventParent # type: ignore
|
||||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||||
|
|
||||||
|
@ -86,6 +90,29 @@ class ProcessInstanceService:
|
||||||
process_model = ProcessModelService.get_process_model(process_model_identifier)
|
process_model = ProcessModelService.get_process_model(process_model_identifier)
|
||||||
return cls.create_process_instance(process_model, user)
|
return cls.create_process_instance(process_model, user)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def waiting_event_can_be_skipped(cls, waiting_event: Dict[str, Any], now_in_utc: datetime) -> bool:
|
||||||
|
#
|
||||||
|
# over time this function can gain more knowledge of different event types,
|
||||||
|
# for now we are just handling Duration Timer events.
|
||||||
|
#
|
||||||
|
# example: {'event_type': 'Duration Timer', 'name': None, 'value': '2023-04-27T20:15:10.626656+00:00'}
|
||||||
|
#
|
||||||
|
event_type = waiting_event.get("event_type")
|
||||||
|
if event_type == "Duration Timer":
|
||||||
|
event_value = waiting_event.get("value")
|
||||||
|
if event_value is not None:
|
||||||
|
event_datetime = TimerEventDefinition.get_datetime(event_value)
|
||||||
|
return event_datetime > now_in_utc # type: ignore
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def all_waiting_events_can_be_skipped(cls, waiting_events: List[Dict[str, Any]]) -> bool:
|
||||||
|
for waiting_event in waiting_events:
|
||||||
|
if not cls.waiting_event_can_be_skipped(waiting_event, datetime.now(timezone.utc)):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def ready_user_task_has_associated_timer(cls, processor: ProcessInstanceProcessor) -> bool:
|
def ready_user_task_has_associated_timer(cls, processor: ProcessInstanceProcessor) -> bool:
|
||||||
for ready_user_task in processor.bpmn_process_instance.get_ready_user_tasks():
|
for ready_user_task in processor.bpmn_process_instance.get_ready_user_tasks():
|
||||||
|
@ -101,7 +128,10 @@ class ProcessInstanceService:
|
||||||
if processor.process_instance_model.status != status_value:
|
if processor.process_instance_model.status != status_value:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return status_value == "user_input_required" and not cls.ready_user_task_has_associated_timer(processor)
|
if status_value == "user_input_required" and cls.ready_user_task_has_associated_timer(processor):
|
||||||
|
return cls.all_waiting_events_can_be_skipped(processor.bpmn_process_instance.waiting_events())
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def do_waiting(cls, status_value: str = ProcessInstanceStatus.waiting.value) -> None:
|
def do_waiting(cls, status_value: str = ProcessInstanceStatus.waiting.value) -> None:
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
"""Test_process_instance_processor."""
|
"""Test_process_instance_processor."""
|
||||||
|
from datetime import datetime
|
||||||
|
from datetime import timezone
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from flask.app import Flask
|
from flask.app import Flask
|
||||||
|
@ -213,3 +215,33 @@ class TestProcessInstanceService(BaseTest):
|
||||||
assert len(models) == 2
|
assert len(models) == 2
|
||||||
self._check_sample_file_data_model("File", 0, models[0])
|
self._check_sample_file_data_model("File", 0, models[0])
|
||||||
self._check_sample_file_data_model("File", 1, models[1])
|
self._check_sample_file_data_model("File", 1, models[1])
|
||||||
|
|
||||||
|
def test_does_not_skip_events_it_does_not_know_about(self) -> None:
|
||||||
|
assert not (
|
||||||
|
ProcessInstanceService.waiting_event_can_be_skipped(
|
||||||
|
{"event_type": "Unknown", "name": None, "value": "2023-04-27T20:15:10.626656+00:00"},
|
||||||
|
datetime.now(timezone.utc),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_does_skip_duration_timer_events_for_the_future(self) -> None:
|
||||||
|
assert ProcessInstanceService.waiting_event_can_be_skipped(
|
||||||
|
{"event_type": "Duration Timer", "name": None, "value": "2023-04-27T20:15:10.626656+00:00"},
|
||||||
|
datetime.fromisoformat("2023-04-26T20:15:10.626656+00:00"),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_does_not_skip_duration_timer_events_for_the_past(self) -> None:
|
||||||
|
assert not (
|
||||||
|
ProcessInstanceService.waiting_event_can_be_skipped(
|
||||||
|
{"event_type": "Duration Timer", "name": None, "value": "2023-04-27T20:15:10.626656+00:00"},
|
||||||
|
datetime.fromisoformat("2023-04-28T20:15:10.626656+00:00"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_does_not_skip_duration_timer_events_for_now(self) -> None:
|
||||||
|
assert not (
|
||||||
|
ProcessInstanceService.waiting_event_can_be_skipped(
|
||||||
|
{"event_type": "Duration Timer", "name": None, "value": "2023-04-27T20:15:10.626656+00:00"},
|
||||||
|
datetime.fromisoformat("2023-04-27T20:15:10.626656+00:00"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue