Skip to content

Commit 412530f

Browse files
authored
fix: scope Cloud Run reconciliation per service
Merging the green per-service reconciliation fix. Matrix deployments now reconcile only their own traffic and legacy scheduler scope, eliminating cross-service update races.
2 parents 57d8ba8 + ee461d7 commit 412530f

4 files changed

Lines changed: 33 additions & 4 deletions

File tree

.github/workflows/sync-cloud-run-env.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -897,7 +897,7 @@ jobs:
897897
SYNC_PLAN_JSON: ${{ steps.strategy_requirements.outputs.sync_plan_json }}
898898
run: |
899899
set -euo pipefail
900-
python3 scripts/reconcile_cloud_runtime.py --platform longbridge --ensure-latest-traffic
900+
python3 scripts/reconcile_cloud_runtime.py --platform longbridge --ensure-latest-traffic --service "${CLOUD_RUN_SERVICE}"
901901
902902
- name: Sync Cloud Scheduler schedule
903903
if: steps.config.outputs.env_sync_enabled == 'true'
@@ -1189,7 +1189,7 @@ jobs:
11891189
SYNC_PLAN_JSON: ${{ steps.strategy_requirements.outputs.sync_plan_json }}
11901190
run: |
11911191
set -euo pipefail
1192-
python3 scripts/reconcile_cloud_runtime.py --platform longbridge --delete-legacy-schedulers
1192+
python3 scripts/reconcile_cloud_runtime.py --platform longbridge --delete-legacy-schedulers --service "${CLOUD_RUN_SERVICE}"
11931193
11941194
- name: Prune old Cloud Run revisions
11951195
if: steps.config.outputs.enabled == 'true'

scripts/reconcile_cloud_runtime.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,17 @@ def load_targets(*, env: Mapping[str, str]) -> list[RuntimeTarget]:
122122
return _dedupe_targets(targets)
123123

124124

125+
def select_targets(targets: Sequence[RuntimeTarget], *, service_name: str = "") -> list[RuntimeTarget]:
126+
"""Optionally restrict reconciliation to one deployment service."""
127+
selected_service = str(service_name or "").strip()
128+
if not selected_service:
129+
return list(targets)
130+
selected = [target for target in targets if target.service_name == selected_service]
131+
if not selected:
132+
raise ReconcileError(f"Requested service {selected_service!r} is not a resolved Cloud Run target")
133+
return selected
134+
135+
125136
def _run(args: Sequence[str], *, json_output: bool = False, dry_run: bool = False) -> Any:
126137
printable = " ".join(args)
127138
if dry_run:
@@ -413,6 +424,7 @@ def parse_args(argv: Sequence[str]) -> argparse.Namespace:
413424
parser.add_argument("--expected-commit", default=os.environ.get("GITHUB_SHA", ""))
414425
parser.add_argument("--expected-release-set", default=os.environ.get("EXPECTED_RELEASE_SET", ""))
415426
parser.add_argument("--expected-image-digest", default=os.environ.get("EXPECTED_IMAGE_DIGEST", ""))
427+
parser.add_argument("--service", default="", help="Restrict reconciliation to one Cloud Run service")
416428
parser.add_argument("--ensure-latest-traffic", action="store_true")
417429
parser.add_argument("--delete-legacy-schedulers", action="store_true")
418430
parser.add_argument("--dry-run", action="store_true")
@@ -426,6 +438,7 @@ def main(argv: Sequence[str] | None = None) -> int:
426438
targets = load_targets(env=os.environ)
427439
if not targets:
428440
raise ReconcileError("No Cloud Run targets resolved from SYNC_PLAN_JSON, CLOUD_RUN_SERVICE_TARGETS_JSON, or CLOUD_RUN_SERVICE")
441+
targets = select_targets(targets, service_name=args.service)
429442
if args.ensure_latest_traffic:
430443
ensure_latest_traffic(
431444
project=args.project,

tests/test_reconcile_cloud_runtime.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,22 @@
88

99

1010
class ReconcileCloudRuntimeTest(unittest.TestCase):
11+
def test_select_targets_restricts_reconciliation_to_requested_service(self) -> None:
12+
targets = [
13+
reconcile.RuntimeTarget(service_name="longbridge-quant-paper-service"),
14+
reconcile.RuntimeTarget(service_name="longbridge-quant-hk-service"),
15+
reconcile.RuntimeTarget(service_name="longbridge-quant-sg-service"),
16+
]
17+
18+
selected = reconcile.select_targets(
19+
targets,
20+
service_name="longbridge-quant-sg-service",
21+
)
22+
23+
self.assertEqual(selected, [reconcile.RuntimeTarget(service_name="longbridge-quant-sg-service")])
24+
with self.assertRaisesRegex(reconcile.ReconcileError, "not a resolved Cloud Run target"):
25+
reconcile.select_targets(targets, service_name="unknown-service")
26+
1127
def test_scheduler_locations_include_cross_region_sources_and_dedupe(self) -> None:
1228
env = {
1329
"CLOUD_RUN_SERVICE_TARGETS_JSON": json.dumps(

tests/test_sync_cloud_run_env_workflow.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,9 @@ grep -Fq 'gcloud scheduler jobs pause "${managed_job_name}"' "$workflow_file"
233233
grep -Fq 'monitor_job_name="longbridge-monitor-dispatcher-scheduler"' "$workflow_file"
234234
grep -Fq 'gcloud scheduler jobs delete "${monitor_job_name}"' "$workflow_file"
235235
grep -Fq 'Reconcile Cloud Run traffic' "$workflow_file"
236-
grep -Fq 'python3 scripts/reconcile_cloud_runtime.py --platform longbridge --ensure-latest-traffic' "$workflow_file"
236+
grep -Fq 'python3 scripts/reconcile_cloud_runtime.py --platform longbridge --ensure-latest-traffic --service "${CLOUD_RUN_SERVICE}"' "$workflow_file"
237237
grep -Fq 'Reconcile legacy Cloud Scheduler jobs' "$workflow_file"
238-
grep -Fq 'python3 scripts/reconcile_cloud_runtime.py --platform longbridge --delete-legacy-schedulers' "$workflow_file"
238+
grep -Fq 'python3 scripts/reconcile_cloud_runtime.py --platform longbridge --delete-legacy-schedulers --service "${CLOUD_RUN_SERVICE}"' "$workflow_file"
239239
grep -Fq -- '--schedule="${desired_schedule}"' "$workflow_file"
240240
grep -Fq -- '--time-zone="${market_timezone}"' "$workflow_file"
241241

0 commit comments

Comments
 (0)