Skip to content

ES blue-green M1: clone-first alias bootstrap (eph-1 rehearsal) - #6255

Merged
johniak merged 13 commits into
ephemeral-1from
es-blue-green
Aug 3, 2026
Merged

ES blue-green M1: clone-first alias bootstrap (eph-1 rehearsal)#6255
johniak merged 13 commits into
ephemeral-1from
es-blue-green

Conversation

@johniak

@johniak johniak commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Milestone 1 of the ES blue-green plan - pure infra, no changes from the blocked PRs (#5912/#5913).

  • es_populate_delta + es_mutate_stream from feat(household): es shadow-cluster delta sync + change-stream tools (master) #6176, with imports fixed for elasticsearch 9 (master dropped elasticsearch_dsl)
  • new es_bootstrap_aliases command: per program x {individuals, households} - write-block -> _clone to <name>_v1 (replicas=0) -> wait active primary -> count sanity -> atomic remove_index+add alias -> unblock + restore replicas; resumable from ES state, ES-index lock, --status/--dry-run, final delta pass sweeps freeze-window writes
  • create_program_indexes now creates _v1 + alias, so new programs are born on the alias scheme
  • automatic destructive entrypoints defused: program-activation signal and rebuild_search_index route through the new non-destructive ensure_program_indexes; rebuild_program_indexes stays destructive only behind the explicit admin button

Rehearsal runbook for eph-1: canary -> verify -> --all with es_mutate_stream running -> chaos checks (kill mid-run, parallel run, program activation mid-test) -> clean --status.

johniak added 9 commits July 9, 2026 11:23
…master)

Master-compatible variant of #6164 (which targets develop). Same two
management commands + tests; only adapted to master's code:
- elasticsearch_dsl import path (es-py 8), not elasticsearch.dsl (es-py 9)
- index_management calls without the develop-only using=/parallel=/thread_count=
  kwargs (#6031 refactor is not on master)
- dropped the _es_shadow v9 wiring (imports elasticsearch.dsl -> ImportError on
  master, and unused in the default-connection setup)

No logic change to the delta itself; 34 tests pass on the ES8 environment.
…nifests, bulk-copy)

README runbook, mutate-data.yml / reindex-delta.yml pod manifests, and
es8_to_es9_migration (Valeriya's raw-HTTP ES8->ES9 bulk copy) + _es_shadow helper.
_es_shadow uses the es-py 8 import path (elasticsearch_dsl) and is not wired into
the delta on master (default connection); kept only for a multi-alias shadow setup.
…ook table

Renumber to 11 sequential steps, drop the duplicated delta row, and update the
command-section step references (final delta is now step 9).
Keep every step the user added as its own row in the same order (delta catch-up
twice: steps 4 and 8, plus final delta at 11); only fix the malformed markdown
rows and renumber 1-12. No reordering, no merging.
…gram indexes

Per index: write-block -> _clone to <name>_v1 (replicas=0) -> wait active primary
-> count sanity -> atomic remove_index+add alias -> unblock + restore replicas.
Resumable from ES state (skip on alias, redo takeover after crash), ES-index lock,
--status/--dry-run, final es_populate_delta pass sweeps freeze-window writes.
create_program_indexes now creates _v1 + alias so new programs are born on the
alias scheme.
…e_program_indexes

Program-activation signal and rebuild_search_index no longer delete a live index:
they use the new non-destructive ensure_program_indexes (create missing _v1+alias,
upsert-populate). rebuild_program_indexes stays destructive but is reserved for the
explicit admin Rebuild Index button, documented as such.
…new no-cover pragmas

The es8->es9 cluster migration is done and nothing imports those files; they were
also the source of the lint/mypy failures. The pragma gate forbids newly added
'pragma: no cover' lines, so the ensure_program_indexes failure branches are now
covered by tests instead.
@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.92%. Comparing base (ae026b2) to head (c4b508f).
⚠️ Report is 14 commits behind head on ephemeral-1.

Additional details and impacted files
@@             Coverage Diff              @@
##           ephemeral-1    #6255   +/-   ##
============================================
  Coverage        96.92%   96.92%           
============================================
  Files              490      490           
  Lines            33304    33319   +15     
  Branches          3940     3942    +2     
============================================
+ Hits             32279    32295   +16     
  Misses             565      565           
+ Partials           460      459    -1     
Flag Coverage Δ
e2e 52.97% <15.00%> (-0.02%) ⬇️
unit 96.62% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…-created indexes

A doc write racing index creation auto-creates a dynamic-mapping index; ensure-style
create-if-missing then skips the proper mapping and search silently returns nothing
(caught by test_search filter tests). rebuild_search_index is an explicit console/dev
recovery tool, so delete->create->populate is the right semantics there. The automatic
path (program-activation signal) stays on ensure_program_indexes.
@johniak
johniak marked this pull request as draft July 28, 2026 10:45
johniak added 2 commits July 28, 2026 13:25
… _v1

A rebuild during a blue-green sanity window (alias on _v2, unaliased _v1 still
lingering) would delete _v2 and then collide creating _v1, stranding the program
with no index and no alias. max(existing)+1 sidesteps the collision.
…elta always runs

- es_bootstrap_aliases: open the dark clone (unblock + replicas) BEFORE the atomic
  takeover so a crash after the swap leaves nothing blocked; any failure before the
  takeover unblocks the still-live source; the alias branch self-heals a lingering
  write block from a crashed older run (S1/G1)
- missing-index branch full-populates instead of leaving an empty index behind a
  successful message (S2)
- the final es_populate_delta pass runs even when some indexes failed, so healthy
  programs don't keep freeze-window drift (S3)
- hard-delete-during-freeze documented as an accepted M1 risk (S4)
- ambiguous --program <code> (unique only per BA) is rejected (S5)
- es_populate_delta propagates --using through create/populate/verify/reconcile and
  bulk writes/deletes (S6)
- es_mutate_stream: deletion opt-in (default 0) and refuses to run outside DEBUG
  without --i-am-sure (S7)
- README rewritten for the M1 alias bootstrap tooling (S8); working-note markers
  removed (S9)
- failure-injection tests: clone/health/alias-API failures unblock the source,
  target opened before takeover, heal path, ambiguous code, DEBUG guard (G2)
@johniak
johniak marked this pull request as ready for review August 3, 2026 13:38
@johniak
johniak merged commit 839b242 into ephemeral-1 Aug 3, 2026
11 checks passed
@johniak
johniak deleted the es-blue-green branch August 3, 2026 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant