Skip to content

Commit f1026d7

Browse files
Pigbibicodex
andcommitted
fix: keep heartbeat dependency-free
Co-Authored-By: Codex <noreply@openai.com>
1 parent 522d6f7 commit f1026d7

3 files changed

Lines changed: 146 additions & 7 deletions

File tree

scripts/execution_report_heartbeat.py

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,97 @@ def _hydrate_runtime_target_schedules(
623623
return hydrated
624624

625625

626+
def _cloud_run_region() -> str:
627+
return (
628+
os.environ.get("RUNTIME_HEARTBEAT_CLOUD_RUN_REGION")
629+
or os.environ.get("CLOUD_RUN_REGION")
630+
or "us-central1"
631+
)
632+
633+
634+
def _describe_cloud_run_service(
635+
service: str,
636+
*,
637+
project: str | None,
638+
) -> dict[str, Any]:
639+
command = [
640+
"gcloud",
641+
"run",
642+
"services",
643+
"describe",
644+
service,
645+
"--region",
646+
_cloud_run_region(),
647+
"--format=json",
648+
]
649+
if project:
650+
command.extend(["--project", project])
651+
result = _run_gcloud(command)
652+
if result.returncode != 0:
653+
detail = (result.stderr or result.stdout or "").strip()
654+
raise RuntimeError(detail or f"gcloud run services describe failed for {service}")
655+
try:
656+
payload = json.loads(result.stdout)
657+
except json.JSONDecodeError as exc:
658+
raise RuntimeError(
659+
f"gcloud run services describe returned invalid JSON for {service}: {exc}"
660+
) from exc
661+
if not isinstance(payload, dict):
662+
raise RuntimeError(f"gcloud run services describe returned no data for {service}")
663+
return payload
664+
665+
666+
def _deployed_runtime_target(payload: dict[str, Any]) -> dict[str, Any]:
667+
template = payload.get("spec", {}).get("template", {})
668+
containers = template.get("spec", {}).get("containers")
669+
if not isinstance(containers, list):
670+
containers = template.get("containers")
671+
for container in containers if isinstance(containers, list) else []:
672+
if not isinstance(container, dict):
673+
continue
674+
for entry in container.get("env") or []:
675+
if not isinstance(entry, dict) or entry.get("name") not in {
676+
"RUNTIME_TARGET_JSON",
677+
"QSL_RUNTIME_TARGET_JSON",
678+
}:
679+
continue
680+
try:
681+
runtime_target = json.loads(str(entry.get("value") or ""))
682+
except json.JSONDecodeError as exc:
683+
raise RuntimeError("deployed runtime target JSON is invalid") from exc
684+
if isinstance(runtime_target, dict):
685+
return runtime_target
686+
return {}
687+
688+
689+
def _hydrate_runtime_target_profiles(
690+
targets: list[dict[str, Any]],
691+
*,
692+
project: str | None,
693+
) -> list[dict[str, Any]]:
694+
hydrated = []
695+
deployed_by_service: dict[str, dict[str, Any]] = {}
696+
for target in targets:
697+
strategy_profile = str(target.get("strategy_profile") or "").strip()
698+
service = str(target.get("service") or "").strip()
699+
if not strategy_profile or not service:
700+
hydrated.append(target)
701+
continue
702+
if service not in deployed_by_service:
703+
deployed_by_service[service] = _deployed_runtime_target(
704+
_describe_cloud_run_service(service, project=project)
705+
)
706+
canonical_profile = str(
707+
deployed_by_service[service].get("strategy_profile") or ""
708+
).strip()
709+
if not canonical_profile:
710+
raise RuntimeError(
711+
f"deployed runtime target has no strategy profile for {service}"
712+
)
713+
hydrated.append({**target, "strategy_profile": canonical_profile})
714+
return hydrated
715+
716+
626717
def _scheduler_job_targets_strategy_run(job: dict[str, Any], service: str) -> bool:
627718
if str(job.get("state") or "").strip().upper() not in {"", "ENABLED"}:
628719
return False
@@ -1045,19 +1136,18 @@ def main(now: dt.datetime | None = None) -> int:
10451136
now = now.replace(tzinfo=dt.timezone.utc)
10461137
now = now.astimezone(dt.timezone.utc)
10471138
since = now - dt.timedelta(hours=lookback_hours)
1048-
from runtime_config_support import resolve_strategy_profile
1049-
1050-
runtime_targets = load_runtime_targets(
1051-
os.environ,
1052-
profile_resolver=resolve_strategy_profile,
1053-
)
1139+
runtime_targets = load_runtime_targets(os.environ)
10541140
try:
1141+
runtime_targets = _hydrate_runtime_target_profiles(
1142+
runtime_targets,
1143+
project=project,
1144+
)
10551145
runtime_targets = _hydrate_runtime_target_schedules(
10561146
runtime_targets,
10571147
project=project,
10581148
)
10591149
except RuntimeError as exc:
1060-
message = f"[Execution Report Heartbeat] {name}\nScheduler policy error: {exc}"
1150+
message = f"[Execution Report Heartbeat] {name}\nRuntime target policy error: {exc}"
10611151
print(message)
10621152
_send_telegram(message)
10631153
return 1 if fail_workflow else 0

tests/test_execution_report_heartbeat.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,49 @@ def test_incomplete_target_schedule_uses_deployed_scheduler_cron(monkeypatch):
696696
assert hydrated[0]["scheduler"]["main_time"] == "45 15 25-29 * *"
697697

698698

699+
def test_target_profile_uses_deployed_canonical_runtime_target(monkeypatch):
700+
monkeypatch.setattr(
701+
heartbeat,
702+
"_describe_cloud_run_service",
703+
lambda *_args, **_kwargs: {
704+
"spec": {
705+
"template": {
706+
"spec": {
707+
"containers": [
708+
{
709+
"env": [
710+
{
711+
"name": "RUNTIME_TARGET_JSON",
712+
"value": json.dumps(
713+
{
714+
"strategy_profile": (
715+
"global_etf_rotation"
716+
)
717+
}
718+
),
719+
}
720+
]
721+
}
722+
]
723+
}
724+
}
725+
}
726+
},
727+
)
728+
729+
hydrated = heartbeat._hydrate_runtime_target_profiles(
730+
[
731+
{
732+
"service": "longbridge-service",
733+
"strategy_profile": "global_macro_etf_rotation",
734+
}
735+
],
736+
project="test-project",
737+
)
738+
739+
assert hydrated[0]["strategy_profile"] == "global_etf_rotation"
740+
741+
699742
def test_main_skips_when_all_configured_targets_are_disabled(monkeypatch, capsys):
700743
_clear_runtime_env(monkeypatch)
701744
monkeypatch.setenv("RUNTIME_HEARTBEAT_NAME", "LongBridge disabled targets")

tests/test_runtime_monitor_workflows.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,9 @@ def test_runtime_monitor_workflows_retry_gcp_authentication() -> None:
2424
assert "id: gcp_auth_primary" in workflow
2525
assert "continue-on-error: true" in workflow
2626
assert "steps.gcp_auth_primary.outcome == 'failure'" in workflow
27+
28+
29+
def test_heartbeat_script_does_not_import_project_runtime_dependencies() -> None:
30+
script = (ROOT / "scripts/execution_report_heartbeat.py").read_text()
31+
32+
assert "from runtime_config_support import" not in script

0 commit comments

Comments
 (0)