Skip to content

Commit 3befc85

Browse files
Pigbibicodex
andcommitted
fix: close runtime heartbeat review gaps
Co-Authored-By: Codex <noreply@openai.com>
1 parent f7acbb3 commit 3befc85

8 files changed

Lines changed: 736 additions & 115 deletions

.github/workflows/execution-report-heartbeat.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,17 @@ jobs:
4545
RUNTIME_HEARTBEAT_MARKET_AWARE: ${{ vars.RUNTIME_HEARTBEAT_MARKET_AWARE || 'true' }}
4646
RUNTIME_HEARTBEAT_MARKET_CALENDAR: ${{ vars.FIRSTRADE_MARKET_CALENDAR }}
4747
RUNTIME_HEARTBEAT_MARKET_TIMEZONE: ${{ vars.FIRSTRADE_MARKET_TIMEZONE }}
48+
RUNTIME_HEARTBEAT_PUBLICATION_GRACE_MINUTES: ${{ vars.RUNTIME_HEARTBEAT_PUBLICATION_GRACE_MINUTES || '30' }}
49+
RUNTIME_HEARTBEAT_SCHEDULER_AWARE: ${{ vars.RUNTIME_HEARTBEAT_SCHEDULER_AWARE || 'true' }}
50+
RUNTIME_HEARTBEAT_SCHEDULER_LOCATION: ${{ vars.RUNTIME_HEARTBEAT_SCHEDULER_LOCATION || vars.CLOUD_RUN_REGION || 'us-central1' }}
4851
RUNTIME_TARGET_ENABLED: ${{ vars.RUNTIME_TARGET_ENABLED }}
4952
RUNTIME_TARGET_JSON: ${{ vars.RUNTIME_TARGET_JSON }}
53+
CLOUD_RUN_REGION: ${{ vars.CLOUD_RUN_REGION }}
5054
CLOUD_RUN_SERVICE: ${{ vars.CLOUD_RUN_SERVICE }}
5155
CLOUD_RUN_SERVICES: ${{ vars.CLOUD_RUN_SERVICES }}
5256
CLOUD_RUN_SERVICE_TARGETS_JSON: ${{ vars.CLOUD_RUN_SERVICE_TARGETS_JSON }}
57+
CLOUD_SCHEDULER_MAIN_TIME: ${{ vars.CLOUD_SCHEDULER_MAIN_TIME }}
58+
EXECUTION_REPORT_GCS_URI: ${{ vars.EXECUTION_REPORT_GCS_URI }}
5359
FIRSTRADE_GCS_STATE_BUCKET: ${{ vars.FIRSTRADE_GCS_STATE_BUCKET }}
5460
FIRSTRADE_STATE_PREFIX: ${{ vars.FIRSTRADE_STATE_PREFIX }}
5561
GLOBAL_TELEGRAM_CHAT_ID: ${{ vars.GLOBAL_TELEGRAM_CHAT_ID }}

scripts/cloud_run_runtime_guard.py

Lines changed: 112 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ def _env_bool(name: str, default: bool = False) -> bool:
4141

4242
def _load_services() -> list[str]:
4343
services = []
44+
enabled_target_services = []
45+
disabled_target_services = []
4446
for name in (
4547
"RUNTIME_GUARD_CLOUD_RUN_SERVICES",
4648
"CLOUD_RUN_SERVICES",
@@ -52,37 +54,27 @@ def _load_services() -> list[str]:
5254
if raw_targets:
5355
try:
5456
payload = json.loads(raw_targets)
57+
defaults = payload.get("defaults") if isinstance(payload, dict) else {}
58+
defaults = defaults if isinstance(defaults, dict) else {}
5559
targets = payload.get("targets") if isinstance(payload, dict) else payload
5660
if isinstance(targets, list):
5761
for target in targets:
5862
if not isinstance(target, dict):
5963
continue
60-
if not _target_enabled(target):
61-
continue
62-
runtime_target = target.get("runtime_target") or target.get(
63-
"runtime_target_json"
64-
)
65-
if isinstance(runtime_target, str):
66-
try:
67-
runtime_target = json.loads(runtime_target)
68-
except json.JSONDecodeError:
69-
runtime_target = {}
70-
for key in ("service", "service_name", "cloud_run_service"):
71-
value = target.get(key) or (
72-
runtime_target.get(key)
73-
if isinstance(runtime_target, dict)
74-
else None
75-
)
76-
if value:
77-
services.extend(_split_values(str(value)))
78-
break
64+
target_services = _target_service_names(target, defaults)
65+
if _target_enabled(target, defaults):
66+
enabled_target_services.extend(target_services)
67+
else:
68+
disabled_target_services.extend(target_services)
7969
except json.JSONDecodeError as exc:
8070
raise RuntimeError(f"CLOUD_RUN_SERVICE_TARGETS_JSON is invalid: {exc}") from exc
8171

72+
services.extend(enabled_target_services)
73+
disabled = set(disabled_target_services) - set(enabled_target_services)
8274
seen = set()
8375
unique = []
8476
for service in services:
85-
if service not in seen:
77+
if service not in seen and service not in disabled:
8678
seen.add(service)
8779
unique.append(service)
8880
return unique
@@ -112,9 +104,29 @@ def _service_job_aliases(service: str) -> list[str]:
112104
def _scheduler_job_pattern_for_services(services: list[str]) -> str:
113105
candidates: list[str] = []
114106
for service in services:
115-
candidates.extend(_service_job_aliases(service))
107+
candidates.extend(_scheduler_job_names(service))
116108
unique = list(dict.fromkeys(candidates))
117-
return "|".join(re.escape(candidate) for candidate in unique)
109+
if not unique:
110+
return ""
111+
return r"^(?:" + "|".join(re.escape(candidate) for candidate in unique) + r")\Z"
112+
113+
114+
def _scheduler_job_names(service: str) -> list[str]:
115+
names = []
116+
for alias in _service_job_aliases(service):
117+
names.extend(
118+
(
119+
f"{alias}-scheduler",
120+
f"{alias}-probe-scheduler",
121+
f"{alias}-precheck-scheduler",
122+
)
123+
)
124+
return list(dict.fromkeys(names))
125+
126+
127+
def _job_matches_service(job_name: str, service: str) -> bool:
128+
normalized = str(job_name or "").strip().rsplit("/", 1)[-1]
129+
return normalized in _scheduler_job_names(service)
118130

119131

120132
def _entry_job_name(entry: dict[str, Any]) -> str:
@@ -131,7 +143,7 @@ def _scheduler_entry_since(
131143
matches = [
132144
service_since
133145
for service, service_since in service_since_by_name.items()
134-
if any(alias and alias in job_name for alias in _service_job_aliases(service))
146+
if _job_matches_service(job_name, service)
135147
]
136148
return max(matches) if matches else fallback
137149

@@ -147,7 +159,7 @@ def _is_duplicate_scheduler_failure(
147159

148160
tolerance = dt.timedelta(seconds=SCHEDULER_CLOUD_RUN_DEDUP_SECONDS)
149161
for service, failures in cloud_run_failures_by_service.items():
150-
if not any(alias and alias in job_name for alias in _service_job_aliases(service)):
162+
if not _job_matches_service(job_name, service):
151163
continue
152164
for failure in failures:
153165
cloud_run_timestamp = _parse_timestamp(failure.get("timestamp"))
@@ -233,22 +245,51 @@ def _format_timestamp(value: dt.datetime) -> str:
233245
return value.astimezone(dt.timezone.utc).isoformat().replace("+00:00", "Z")
234246

235247

236-
def _target_payloads() -> list[dict[str, Any]]:
248+
def _target_configuration() -> tuple[list[dict[str, Any]], dict[str, Any]]:
237249
raw_targets = (os.environ.get("CLOUD_RUN_SERVICE_TARGETS_JSON") or "").strip()
238250
if not raw_targets:
239-
return []
251+
return [], {}
240252
try:
241253
payload = json.loads(raw_targets)
242254
except json.JSONDecodeError:
243-
return []
255+
return [], {}
256+
defaults = payload.get("defaults") if isinstance(payload, dict) else {}
257+
defaults = defaults if isinstance(defaults, dict) else {}
244258
targets = payload.get("targets") if isinstance(payload, dict) else payload
245259
if not isinstance(targets, list):
246-
return []
247-
return [target for target in targets if isinstance(target, dict)]
260+
return [], defaults
261+
return [target for target in targets if isinstance(target, dict)], defaults
248262

249263

250-
def _runtime_target(target: dict[str, Any]) -> dict[str, Any]:
251-
runtime_target = target.get("runtime_target") or target.get("runtime_target_json")
264+
def _target_payloads() -> list[dict[str, Any]]:
265+
targets, _defaults = _target_configuration()
266+
return targets
267+
268+
269+
def _target_field(
270+
target: dict[str, Any],
271+
defaults: dict[str, Any],
272+
*names: str,
273+
) -> Any:
274+
target_env = target.get("env") if isinstance(target.get("env"), dict) else {}
275+
defaults_env = defaults.get("env") if isinstance(defaults.get("env"), dict) else {}
276+
for source in (target, target_env, defaults, defaults_env):
277+
for name in names:
278+
if name in source:
279+
return source[name]
280+
return None
281+
282+
283+
def _runtime_target(
284+
target: dict[str, Any],
285+
defaults: dict[str, Any] | None = None,
286+
) -> dict[str, Any]:
287+
runtime_target = _target_field(
288+
target,
289+
defaults or {},
290+
"runtime_target",
291+
"runtime_target_json",
292+
)
252293
if isinstance(runtime_target, str):
253294
try:
254295
runtime_target = json.loads(runtime_target)
@@ -268,32 +309,57 @@ def _coerce_bool(value: Any, default: bool) -> bool:
268309
return text in {"1", "true", "yes", "y", "on"}
269310

270311

271-
def _target_enabled(target: dict[str, Any]) -> bool:
272-
runtime_target = _runtime_target(target)
312+
def _target_enabled(
313+
target: dict[str, Any],
314+
defaults: dict[str, Any] | None = None,
315+
) -> bool:
316+
defaults = defaults or {}
317+
runtime_target = _runtime_target(target, defaults)
318+
value = _target_field(
319+
target,
320+
defaults,
321+
"runtime_target_enabled",
322+
"RUNTIME_TARGET_ENABLED",
323+
)
324+
if value is not None:
325+
return _coerce_bool(value, True)
273326
for key in ("runtime_target_enabled", "RUNTIME_TARGET_ENABLED"):
274-
if key in target:
275-
return _coerce_bool(target.get(key), True)
276327
if key in runtime_target:
277328
return _coerce_bool(runtime_target.get(key), True)
278329
return True
279330

280331

281-
def _target_service_names(target: dict[str, Any]) -> list[str]:
282-
runtime_target = _runtime_target(target)
283-
for key in ("service", "service_name", "cloud_run_service"):
284-
value = target.get(key) or runtime_target.get(key)
285-
if value:
286-
return _split_values(str(value))
332+
def _target_service_names(
333+
target: dict[str, Any],
334+
defaults: dict[str, Any] | None = None,
335+
) -> list[str]:
336+
defaults = defaults or {}
337+
runtime_target = _runtime_target(target, defaults)
338+
value = _target_field(
339+
target,
340+
defaults,
341+
"service",
342+
"service_name",
343+
"cloud_run_service",
344+
)
345+
if value is None:
346+
for key in ("service", "service_name", "cloud_run_service"):
347+
if runtime_target.get(key):
348+
value = runtime_target[key]
349+
break
350+
if value:
351+
return _split_values(str(value))
287352
return []
288353

289354

290355
def _region_for_service(service: str) -> str:
291-
for target in _target_payloads():
292-
if service not in _target_service_names(target):
356+
targets, defaults = _target_configuration()
357+
for target in targets:
358+
if service not in _target_service_names(target, defaults):
293359
continue
294-
runtime_target = _runtime_target(target)
360+
runtime_target = _runtime_target(target, defaults)
295361
for key in ("region", "cloud_run_region", "location"):
296-
value = target.get(key) or runtime_target.get(key)
362+
value = _target_field(target, defaults, key) or runtime_target.get(key)
297363
if value:
298364
return str(value).strip()
299365
return (
@@ -596,7 +662,7 @@ def main() -> int:
596662
entries = [
597663
entry
598664
for entry in entries
599-
if regex.search(str(_labels(entry).get("job_id") or _labels(entry).get("job_name") or ""))
665+
if regex.search(_entry_job_name(entry).rsplit("/", 1)[-1])
600666
]
601667
failures = []
602668
for entry in entries:

0 commit comments

Comments
 (0)