Preskoči na sadržaj

State write protocol — dual-write contract

TL;DR

Business verbs (bump, seed, build, scan, deploy, pipeline notify) pišu u oba: canonical ci-state.json + per-service shard ci-state.<svc>.<env>[.<platform>].json. Preko pipeline_state.write_state_with_mirrors. Razlog: shard-glob fan-in (merge-state) hvata i raw canonical writes.

Problem bez dual-write

Pipeline A (parallel shard):  piše ci-state.api.staging.json
Pipeline B (canonical flow):  piše ci-state.json

Poslije: merge-state hvata ci-state.api.staging.json ALI NE
         ci-state.json (jedna tačka u imenu, glob ne matchuje).

Rezultat: A-ov contribution propao.

Rješenje

from ci.pipeline_state import write_state_with_mirrors

# Svaki verb radi:
write_state_with_mirrors(
    state=state,
    canonical_path="ci-state.json",
    services=("api", "worker"),
    env="staging",
)
# → piše ci-state.json (canonical) + ci-state.api.staging.json + ci-state.worker.staging.json

Atomic write za oba:

  1. Temp file u istom dir-u (ci-state.json.tmp, ci-state.<svc>.<env>.json.tmp).
  2. os.replace(tmp, target) — POSIX atomic rename.

Tri ograničenja

  • merge-state NE koristi business-verb write path. Fan-in verb ima svoj read+merge; ne poziva write_state_with_mirrors.
  • Dual-write je compatibility bridge, ne zamjena za shard-based fan-in. Paralelni step-ovi se i dalje oslanjaju na shard-ove + merge-state.
  • Canonical ci-state.json NIJE parallel-safe coordination surface. Za paralelne koriste se shard-ovi.

Shard path format

ci-state.json                       # canonical
ci-state.<svc>.<env>.json           # per-service, per-env
ci-state.<svc>.<env>.<platform>.json  # EAS deploy (per-platform)

Primjeri:

ci-state.json                       # canonical
ci-state.api.staging.json           # api @ staging
ci-state.mobile.production.ios.json # mobile @ production, iOS only
ci-state.mobile.production.android.json # mobile @ production, Android

Discovery: pipeline_state.is_shard_path(path)ci-state.X.Y.json (sa najmanje 2 tačke) je shard; ci-state.json (sa 1 tačkom) je canonical.

Šta NE piše u state

  • make ci-state-merge — čita, ne piše (samo merge-uje shard-ove u canonical).
  • ci/state.py CLI read — samo čita.
  • bin/design, bin/check_arch_reminder.py — ne diraju state.

Failure modes

  • Temp file write fail (disk full) → state write fail-uje; verb aborta, retry.
  • Rename fail (permission) → verb aborta, ne partial-write.
  • Shard dir ne postojios.makedirs(parent, exist_ok=True).

Vidi i