Skip to content

Commit 33c36a3

Browse files
committed
Refactor report rerun orchestration services
1 parent c6281b5 commit 33c36a3

4 files changed

Lines changed: 272 additions & 360 deletions

File tree

policyengine_api/services/report_output_service.py

Lines changed: 29 additions & 250 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import uuid
21
from datetime import datetime, timezone
32

43
from sqlalchemy.engine.row import Row
@@ -640,205 +639,18 @@ def _insert_bootstrap_report_run(
640639
report_spec: ReportSpec | None,
641640
version_manifest: dict[str, str | None],
642641
) -> None:
643-
requested_at = self._utc_timestamp()
644-
is_terminal = report_output["status"] in ("complete", "error")
645-
has_started = report_output["status"] in ("running", "complete", "error")
646-
started_at = requested_at if has_started else None
647-
finished_at = requested_at if is_terminal else None
648-
649-
tx.query(
650-
"""
651-
INSERT INTO report_output_runs (
652-
id, report_output_id, run_sequence, status, output, error_message,
653-
trigger_type, requested_at, started_at, finished_at, source_run_id,
654-
report_spec_snapshot_json, country_package_version, policyengine_version,
655-
data_version, runtime_app_name, report_cache_version,
656-
simulation_cache_version, requested_version_override, resolved_dataset,
657-
resolved_options_hash
658-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
659-
""",
660-
(
661-
str(uuid.uuid4()),
662-
report_output["id"],
663-
1,
664-
report_output["status"],
665-
serialize_json_field(report_output.get("output")),
666-
report_output.get("error_message"),
667-
"initial",
668-
requested_at,
669-
started_at,
670-
finished_at,
671-
None,
672-
(report_spec.model_dump_json() if report_spec is not None else None),
673-
version_manifest["country_package_version"],
674-
version_manifest["policyengine_version"],
675-
version_manifest["data_version"],
676-
version_manifest["runtime_app_name"],
677-
version_manifest["report_cache_version"],
678-
version_manifest["simulation_cache_version"],
679-
version_manifest["requested_version_override"],
680-
version_manifest["resolved_dataset"],
681-
version_manifest["resolved_options_hash"],
682-
),
683-
)
684-
685-
def _insert_report_run_in_transaction(
686-
self,
687-
tx,
688-
report_output: dict,
689-
*,
690-
status: str,
691-
trigger_type: str,
692-
source_run_id: str | None,
693-
report_spec: ReportSpec | None,
694-
version_manifest: dict[str, str | None],
695-
) -> str:
696-
run_sequence_row: Row | None = tx.query(
697-
"""
698-
SELECT COALESCE(MAX(run_sequence), 0) AS max_run_sequence
699-
FROM report_output_runs
700-
WHERE report_output_id = ?
701-
""",
702-
(report_output["id"],),
703-
).fetchone()
704-
run_sequence = (
705-
int(run_sequence_row["max_run_sequence"]) + 1
706-
if run_sequence_row is not None
707-
else 1
708-
)
709-
run_id = str(uuid.uuid4())
710-
requested_at = self._utc_timestamp()
711-
is_terminal = status in ("complete", "error")
712-
has_started = status in ("running", "complete", "error")
713-
started_at = requested_at if has_started else None
714-
finished_at = requested_at if is_terminal else None
715-
716-
tx.query(
717-
"""
718-
INSERT INTO report_output_runs (
719-
id, report_output_id, run_sequence, status, output, error_message,
720-
trigger_type, requested_at, started_at, finished_at, source_run_id,
721-
report_spec_snapshot_json, country_package_version, policyengine_version,
722-
data_version, runtime_app_name, report_cache_version,
723-
simulation_cache_version, requested_version_override, resolved_dataset,
724-
resolved_options_hash
725-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
726-
""",
727-
(
728-
run_id,
729-
report_output["id"],
730-
run_sequence,
731-
status,
732-
None,
733-
None,
734-
trigger_type,
735-
requested_at,
736-
started_at,
737-
finished_at,
738-
source_run_id,
739-
(report_spec.model_dump_json() if report_spec is not None else None),
740-
version_manifest["country_package_version"],
741-
version_manifest["policyengine_version"],
742-
version_manifest["data_version"],
743-
version_manifest["runtime_app_name"],
744-
version_manifest["report_cache_version"],
745-
version_manifest["simulation_cache_version"],
746-
version_manifest["requested_version_override"],
747-
version_manifest["resolved_dataset"],
748-
version_manifest["resolved_options_hash"],
749-
),
750-
)
751-
return run_id
752-
753-
def _select_simulation_display_run(
754-
self,
755-
simulation: dict,
756-
runs_descending: list[dict],
757-
) -> dict | None:
758-
active_run_id = simulation.get("active_run_id")
759-
if active_run_id is not None:
760-
for run in runs_descending:
761-
if run["id"] == active_run_id:
762-
return run
763-
764-
latest_successful_run_id = simulation.get("latest_successful_run_id")
765-
if latest_successful_run_id is not None:
766-
for run in runs_descending:
767-
if run["id"] == latest_successful_run_id:
768-
return run
769-
770-
return runs_descending[0] if runs_descending else None
771-
772-
def _insert_simulation_run_in_transaction(
773-
self,
774-
tx,
775-
simulation: dict,
776-
*,
777-
report_output_run_id: str,
778-
input_position: int,
779-
source_run: dict | None,
780-
) -> str:
781-
simulation_spec = (
782-
self.simulation_service._upsert_simulation_spec_in_transaction(
783-
tx,
784-
simulation,
785-
)
786-
)
787-
version_manifest = (
788-
self.simulation_service._build_existing_run_version_manifest(
789-
source_run,
790-
simulation,
791-
)
792-
if source_run is not None
793-
else self.simulation_service._build_bootstrap_version_manifest(simulation)
794-
)
795-
run_sequence_row: Row | None = tx.query(
796-
"""
797-
SELECT COALESCE(MAX(run_sequence), 0) AS max_run_sequence
798-
FROM simulation_runs
799-
WHERE simulation_id = ?
800-
""",
801-
(simulation["id"],),
802-
).fetchone()
803-
run_sequence = (
804-
int(run_sequence_row["max_run_sequence"]) + 1
805-
if run_sequence_row is not None
806-
else 1
807-
)
808-
run_id = str(uuid.uuid4())
809-
tx.query(
810-
"""
811-
INSERT INTO simulation_runs (
812-
id, simulation_id, report_output_run_id, input_position, run_sequence,
813-
status, output, error_message, trigger_type, requested_at, started_at,
814-
finished_at, source_run_id, simulation_spec_snapshot_json,
815-
country_package_version, policyengine_version, data_version,
816-
runtime_app_name, simulation_cache_version
817-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
818-
""",
819-
(
820-
run_id,
821-
simulation["id"],
822-
report_output_run_id,
823-
input_position,
824-
run_sequence,
825-
"pending",
826-
None,
827-
None,
828-
"report_rerun",
829-
self._utc_timestamp(),
830-
None,
831-
None,
832-
source_run["id"] if source_run is not None else None,
833-
simulation_spec.model_dump_json(),
834-
version_manifest["country_package_version"],
835-
version_manifest["policyengine_version"],
836-
version_manifest["data_version"],
837-
version_manifest["runtime_app_name"],
838-
version_manifest["simulation_cache_version"],
642+
self.report_run_service.create_report_output_run_in_transaction(
643+
tx,
644+
report_output["id"],
645+
status=report_output["status"],
646+
trigger_type="initial",
647+
output=report_output.get("output"),
648+
error_message=report_output.get("error_message"),
649+
report_spec_snapshot=(
650+
report_spec.model_dump() if report_spec is not None else None
839651
),
652+
version_manifest=version_manifest,
840653
)
841-
return run_id
842654

843655
def _update_report_run_in_transaction(
844656
self,
@@ -1752,17 +1564,24 @@ def tx_callback(tx):
17521564
version_manifest_overrides=version_manifest_overrides,
17531565
)
17541566
)
1755-
report_run_id = self._insert_report_run_in_transaction(
1756-
tx,
1757-
canonical_report,
1758-
status="pending",
1759-
trigger_type="rerun",
1760-
source_run_id=(
1761-
source_report_run["id"] if source_report_run is not None else None
1762-
),
1763-
report_spec=report_spec,
1764-
version_manifest=report_version_manifest,
1567+
report_run = (
1568+
self.report_run_service.create_report_output_run_in_transaction(
1569+
tx,
1570+
canonical_report_id,
1571+
status="pending",
1572+
trigger_type="rerun",
1573+
source_run_id=(
1574+
source_report_run["id"]
1575+
if source_report_run is not None
1576+
else None
1577+
),
1578+
report_spec_snapshot=(
1579+
report_spec.model_dump() if report_spec is not None else None
1580+
),
1581+
version_manifest=report_version_manifest,
1582+
)
17651583
)
1584+
report_run_id = report_run["id"]
17661585

17671586
simulation_run_ids: list[str] = []
17681587
for input_position, simulation in (
@@ -1772,53 +1591,13 @@ def tx_callback(tx):
17721591
if simulation is None:
17731592
continue
17741593

1775-
simulation_runs_descending = (
1776-
self.simulation_service._list_simulation_runs_descending(
1777-
simulation["id"],
1778-
queryer=tx,
1779-
)
1780-
)
1781-
source_simulation_run = self._select_simulation_display_run(
1782-
simulation,
1783-
simulation_runs_descending,
1784-
)
1785-
simulation_run_id = self._insert_simulation_run_in_transaction(
1594+
simulation_run = self.simulation_service.create_report_rerun_simulation_run_in_transaction(
17861595
tx,
17871596
simulation,
17881597
report_output_run_id=report_run_id,
17891598
input_position=input_position,
1790-
source_run=source_simulation_run,
1791-
)
1792-
simulation_run_ids.append(simulation_run_id)
1793-
1794-
simulation["status"] = "pending"
1795-
simulation["output"] = None
1796-
simulation["error_message"] = None
1797-
simulation_runs_descending = (
1798-
self.simulation_service._list_simulation_runs_descending(
1799-
simulation["id"],
1800-
queryer=tx,
1801-
)
1802-
)
1803-
self.simulation_service._sync_parent_pointers_in_transaction(
1804-
tx,
1805-
simulation,
1806-
simulation_runs_descending,
1807-
)
1808-
tx.query(
1809-
"""
1810-
UPDATE simulations
1811-
SET status = ?, output = ?, error_message = ?
1812-
WHERE id = ? AND country_id = ?
1813-
""",
1814-
(
1815-
"pending",
1816-
None,
1817-
None,
1818-
simulation["id"],
1819-
country_id,
1820-
),
18211599
)
1600+
simulation_run_ids.append(simulation_run["id"])
18221601

18231602
canonical_report["status"] = "pending"
18241603
canonical_report["output"] = None

0 commit comments

Comments
 (0)