From ee461d7a6934795271f759d077df978f5ece9ec7 Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Mon, 24 Aug 2026 18:49:03 +0800 Subject: [PATCH] fix: scope Cloud Run reconciliation per service Co-Authored-By: Codex --- .github/workflows/sync-cloud-run-env.yml | 4 ++-- scripts/reconcile_cloud_runtime.py | 13 +++++++++++++ tests/test_reconcile_cloud_runtime.py | 16 ++++++++++++++++ tests/test_sync_cloud_run_env_workflow.sh | 4 ++-- 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/.github/workflows/sync-cloud-run-env.yml b/.github/workflows/sync-cloud-run-env.yml index 3b8407f..15fb3e5 100644 --- a/.github/workflows/sync-cloud-run-env.yml +++ b/.github/workflows/sync-cloud-run-env.yml @@ -897,7 +897,7 @@ jobs: SYNC_PLAN_JSON: ${{ steps.strategy_requirements.outputs.sync_plan_json }} run: | set -euo pipefail - python3 scripts/reconcile_cloud_runtime.py --platform longbridge --ensure-latest-traffic + python3 scripts/reconcile_cloud_runtime.py --platform longbridge --ensure-latest-traffic --service "${CLOUD_RUN_SERVICE}" - name: Sync Cloud Scheduler schedule if: steps.config.outputs.env_sync_enabled == 'true' @@ -1189,7 +1189,7 @@ jobs: SYNC_PLAN_JSON: ${{ steps.strategy_requirements.outputs.sync_plan_json }} run: | set -euo pipefail - python3 scripts/reconcile_cloud_runtime.py --platform longbridge --delete-legacy-schedulers + python3 scripts/reconcile_cloud_runtime.py --platform longbridge --delete-legacy-schedulers --service "${CLOUD_RUN_SERVICE}" - name: Prune old Cloud Run revisions if: steps.config.outputs.enabled == 'true' diff --git a/scripts/reconcile_cloud_runtime.py b/scripts/reconcile_cloud_runtime.py index dc6bbf4..133db6f 100755 --- a/scripts/reconcile_cloud_runtime.py +++ b/scripts/reconcile_cloud_runtime.py @@ -122,6 +122,17 @@ def load_targets(*, env: Mapping[str, str]) -> list[RuntimeTarget]: return _dedupe_targets(targets) +def select_targets(targets: Sequence[RuntimeTarget], *, service_name: str = "") -> list[RuntimeTarget]: + """Optionally restrict reconciliation to one deployment service.""" + selected_service = str(service_name or "").strip() + if not selected_service: + return list(targets) + selected = [target for target in targets if target.service_name == selected_service] + if not selected: + raise ReconcileError(f"Requested service {selected_service!r} is not a resolved Cloud Run target") + return selected + + def _run(args: Sequence[str], *, json_output: bool = False, dry_run: bool = False) -> Any: printable = " ".join(args) if dry_run: @@ -413,6 +424,7 @@ def parse_args(argv: Sequence[str]) -> argparse.Namespace: parser.add_argument("--expected-commit", default=os.environ.get("GITHUB_SHA", "")) parser.add_argument("--expected-release-set", default=os.environ.get("EXPECTED_RELEASE_SET", "")) parser.add_argument("--expected-image-digest", default=os.environ.get("EXPECTED_IMAGE_DIGEST", "")) + parser.add_argument("--service", default="", help="Restrict reconciliation to one Cloud Run service") parser.add_argument("--ensure-latest-traffic", action="store_true") parser.add_argument("--delete-legacy-schedulers", action="store_true") parser.add_argument("--dry-run", action="store_true") @@ -426,6 +438,7 @@ def main(argv: Sequence[str] | None = None) -> int: targets = load_targets(env=os.environ) if not targets: raise ReconcileError("No Cloud Run targets resolved from SYNC_PLAN_JSON, CLOUD_RUN_SERVICE_TARGETS_JSON, or CLOUD_RUN_SERVICE") + targets = select_targets(targets, service_name=args.service) if args.ensure_latest_traffic: ensure_latest_traffic( project=args.project, diff --git a/tests/test_reconcile_cloud_runtime.py b/tests/test_reconcile_cloud_runtime.py index 42867a0..f5acebc 100644 --- a/tests/test_reconcile_cloud_runtime.py +++ b/tests/test_reconcile_cloud_runtime.py @@ -8,6 +8,22 @@ class ReconcileCloudRuntimeTest(unittest.TestCase): + def test_select_targets_restricts_reconciliation_to_requested_service(self) -> None: + targets = [ + reconcile.RuntimeTarget(service_name="longbridge-quant-paper-service"), + reconcile.RuntimeTarget(service_name="longbridge-quant-hk-service"), + reconcile.RuntimeTarget(service_name="longbridge-quant-sg-service"), + ] + + selected = reconcile.select_targets( + targets, + service_name="longbridge-quant-sg-service", + ) + + self.assertEqual(selected, [reconcile.RuntimeTarget(service_name="longbridge-quant-sg-service")]) + with self.assertRaisesRegex(reconcile.ReconcileError, "not a resolved Cloud Run target"): + reconcile.select_targets(targets, service_name="unknown-service") + def test_scheduler_locations_include_cross_region_sources_and_dedupe(self) -> None: env = { "CLOUD_RUN_SERVICE_TARGETS_JSON": json.dumps( diff --git a/tests/test_sync_cloud_run_env_workflow.sh b/tests/test_sync_cloud_run_env_workflow.sh index 4824d3c..127863a 100644 --- a/tests/test_sync_cloud_run_env_workflow.sh +++ b/tests/test_sync_cloud_run_env_workflow.sh @@ -233,9 +233,9 @@ grep -Fq 'gcloud scheduler jobs pause "${managed_job_name}"' "$workflow_file" grep -Fq 'monitor_job_name="longbridge-monitor-dispatcher-scheduler"' "$workflow_file" grep -Fq 'gcloud scheduler jobs delete "${monitor_job_name}"' "$workflow_file" grep -Fq 'Reconcile Cloud Run traffic' "$workflow_file" -grep -Fq 'python3 scripts/reconcile_cloud_runtime.py --platform longbridge --ensure-latest-traffic' "$workflow_file" +grep -Fq 'python3 scripts/reconcile_cloud_runtime.py --platform longbridge --ensure-latest-traffic --service "${CLOUD_RUN_SERVICE}"' "$workflow_file" grep -Fq 'Reconcile legacy Cloud Scheduler jobs' "$workflow_file" -grep -Fq 'python3 scripts/reconcile_cloud_runtime.py --platform longbridge --delete-legacy-schedulers' "$workflow_file" +grep -Fq 'python3 scripts/reconcile_cloud_runtime.py --platform longbridge --delete-legacy-schedulers --service "${CLOUD_RUN_SERVICE}"' "$workflow_file" grep -Fq -- '--schedule="${desired_schedule}"' "$workflow_file" grep -Fq -- '--time-zone="${market_timezone}"' "$workflow_file"