diff --git a/emap-setup/emap_runner/runner.py b/emap-setup/emap_runner/runner.py index ac42db116..f6d317c7b 100644 --- a/emap-setup/emap_runner/runner.py +++ b/emap-setup/emap_runner/runner.py @@ -1,4 +1,5 @@ import argparse +from datetime import timedelta from pathlib import Path from typing import Any @@ -100,8 +101,15 @@ def create_parser() -> Parser: default=False, action="store_true", ) + validation_parser.add_argument( + "--timeout", + type=lambda h: timedelta(hours=float(h)), + metavar="HOURS", + help="Max time to wait for the validation run to finish", + default=timedelta(hours=10), + ) - # add use-FOO and no-use-FOO options for enabling/disabling various services in validation + # flags for enabling/disabling various services in validation add_boolean_optional_action(validation_parser, "hl7-reader", True, "the main HL7 ADT reader") add_boolean_optional_action(validation_parser, "hoover", True, "the hoover service") add_boolean_optional_action(validation_parser, "waveform", False, "waveform reader") @@ -212,6 +220,7 @@ def validation(self) -> ValidationRunner: use_hl7_reader=self.args.use_hl7_reader, use_hoover=self.args.use_hoover, use_waveform=self.args.use_waveform, + timeout=self.args.timeout, ) runner.run() return runner diff --git a/emap-setup/emap_runner/validation/validation_runner.py b/emap-setup/emap_runner/validation/validation_runner.py index b0b7ed116..3c69419af 100644 --- a/emap-setup/emap_runner/validation/validation_runner.py +++ b/emap-setup/emap_runner/validation/validation_runner.py @@ -13,7 +13,6 @@ class ValidationRunnerException(EMAPRunnerException): class ValidationRunner: - timeout = timedelta(hours=10) wait_secs = 120 final_wait_secs = 600 @@ -21,6 +20,7 @@ def __init__( self, docker_runner: "DockerRunner", time_window: "TimeWindow", + timeout: timedelta, should_build: bool = True, use_hl7_reader: bool = True, use_hoover: bool = True, @@ -35,6 +35,7 @@ def __init__( self.docker = docker_runner self.time_window = time_window + self.timeout = timeout def run(self) -> None: """Run a validation run pipeline by constructing services and waiting @@ -180,11 +181,11 @@ def _wait_for_queue_to_empty(self) -> None: while self._has_populated_queues: time.sleep(ValidationRunner.wait_secs) elapsed_time = timedelta(seconds=time.monotonic() - start_time_monotonic) - if elapsed_time > ValidationRunner.timeout: + if elapsed_time > self.timeout: self._save_logs_and_stop() raise ValidationRunnerException( f"Waiting for queue timed out. Elapsed time " - f"({elapsed_time}) > timeout ({ValidationRunner.timeout})" + f"({elapsed_time}) > timeout ({self.timeout})" ) # exits too keenly from databaseExtracts queue, adding in a wait period diff --git a/emap-setup/tests/test_runner.py b/emap-setup/tests/test_runner.py index e44cf8e7c..94ce9cf9d 100644 --- a/emap-setup/tests/test_runner.py +++ b/emap-setup/tests/test_runner.py @@ -92,6 +92,7 @@ def test_time_window_is_set(): runner = ValidationRunner( docker_runner=DockerRunner(project_dir=Path.cwd(), config=config), time_window=TimeWindow(start_date="today", end_date="7 days ago"), + timeout=timedelta(minutes=3), ) mkdir("config") @@ -149,7 +150,7 @@ def test_validation_source_arguments_set_correct_runner_attributes(args_list, ]) def test_validation_timeout(num_trues, timeout_seconds, expect_raises): parser = create_parser() - args = parser.parse_args(["validation", "--use-waveform"]) + args = parser.parse_args(["validation", "--use-waveform", "--timeout", str(timeout_seconds / 3600)]) global_config = GlobalConfiguration(config_path_all) # simulate having to go through the check and wait loop a variable number of times @@ -162,7 +163,7 @@ def inner_mock_has_populated_queues(): return call_count <= num_trues return inner_mock_has_populated_queues - with patch.multiple(ValidationRunner, timeout=timedelta(seconds=timeout_seconds), wait_secs=0.6, final_wait_secs=0): + with patch.multiple(ValidationRunner, wait_secs=0.6, final_wait_secs=0): with patch.object(ValidationRunner, '_run_emap', new_callable=MagicMock) as run_emap: with patch.object(ValidationRunner, '_has_populated_queues', new_callable=PropertyMock) as populated_queues: with patch.object(ValidationRunner, '_save_logs_and_stop', new_callable=MagicMock) as stop: