Skip to content

fix(weather): spawn-context process pool; station mode runs thread executor#100

Merged
helloiamvu merged 2 commits into
mainfrom
phase28/station-thread-executor
Jul 5, 2026
Merged

fix(weather): spawn-context process pool; station mode runs thread executor#100
helloiamvu merged 2 commits into
mainfrom
phase28/station-thread-executor

Conversation

@helloiamvu

Copy link
Copy Markdown
Member

Why

First station-mode fleet run (weather-backfill-station-28734758679, right after #99 merged) died instantly: every task hit BrokenProcessPool and exited "0 slices completed, 0 rows written" in 0.2s — 5 tasks reported SUCCEEDED having done nothing.

Root cause: --progress-bucket starts the GcsProgressStore gRPC client threads at CLI startup; ProcessPoolExecutor then forks (Linux default) and children inherit a torn copy of those threads' locks → instant pool breakage. Why nothing caught it: macOS defaults to spawn (local tests pass), and CI's process-pool test runs without a progress bucket, so no gRPC threads exist pre-fork. The --executor process flag came from #99's station mode; the old pilots used threads, which is why they never hit it.

What

  • _backfill._make_executor: pin mp_context=spawn for the process pool. _run_slice + item tuple are module-level/picklable by design (P1-1), so spawn is safe. Regression test pins the start method; the existing end-to-end process test passes under spawn.
  • run-weather-backfill.yml station mode: drop --executor process → default thread executor, the proven prod path (2024 pilot processed + uploaded DSRF with threads; numpy/h5py release the GIL for decode). Re-enable process only after spawn is proven in a container.

Evidence

Broken run's Cloud Logging shows the gRPC fork warnings + BrokenProcessPool tracebacks + "0 slices" exits. No progress corruption: the only markers written (DSRF 2017 Jan–Apr local-only) are legitimately empty pre-first-light months; resume is safe.

TS Parity

python_only: true — internal satellite backfill executor + ops workflow; no public API surface, no TS equivalent (TS SDK has no satellite ingest).

🤖 Generated with Claude Code

…ecutor

Live outage on the first station-mode fleet run (job
weather-backfill-station-28734758679, 2026-07-05): every task died with
BrokenProcessPool and exited "0 slices completed, 0 rows written" in
0.2s — 5 tasks reported SUCCEEDED having done nothing.

Root cause: --progress-bucket starts the GcsProgressStore gRPC client
threads at CLI startup; ProcessPoolExecutor then forks (Linux default
start method) and the children inherit a torn copy of those threads'
locks -> instant pool breakage. Never reproduced locally (macOS defaults
to spawn) or in CI (the process-pool test runs without a progress
bucket, so no gRPC threads exist pre-fork).

- _backfill._make_executor: pin mp_context=spawn for the process pool.
  _run_slice + its item tuple are module-level/picklable by design
  (P1-1), so spawn is safe. Regression test pins the start method and
  the existing end-to-end process test still passes under spawn.
- run-weather-backfill.yml station mode: drop --executor process; run
  the default THREAD executor — the proven prod path (the 2024 pilot
  processed + uploaded DSRF with threads; numpy/h5py release the GIL for
  the heavy decode). Re-enable process only after the spawn path is
  proven in a container.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@helloiamvu helloiamvu requested a review from Tarabcak July 5, 2026 08:37
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown

📝 Docs-required check: REMINDER

API-surface change without docs and no opt-out — surfacing reminder.

API-surface files changed:

packages/weather/src/mostlyright/weather/satellite/_backfill.py

Docs files changed:

(none)

Docs surfaces to consider

  • CHANGELOG.md — every behavior change goes here. Auto-synced to the docs site on every release.
  • docs/ — hand-authored prose. Lifted into the landing repo as MDX on every release.
  • Per-package READMEs (packages/*/README.md, packages-ts/*/README.md) — front-door copy on PyPI / npm.
  • Docstrings (Python """ ... """ / TypeScript JSDoc /** ... */) — propagate to the auto-generated API reference via Sphinx / TypeDoc.

How to silence this reminder

  • Add a docs change to this PR (any *.md / *.mdx under docs/, or CHANGELOG.md, or any README.md).
  • Apply the docs-not-required label.
  • Add a line to the PR body: docs-not-required: <one-sentence reason>.

This check is advisory — it never blocks the merge.

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown

Parity ticket gate: PASSED

parity-ticket-check: PR does not touch parity-trigger surface; gate skipped.

See CROSS-SDK-SYNC.md §2 for the workflow.

… boundary

Codex P2 on the spawn-context change: with spawn, pool children re-import
_backfill fresh, so test_process_executor_for_dsrf's parent-side
mock.patch of backfill_goes_satellite never reached them — the
"network-free" test silently ran the real 2024 GOES DSRF transport
(macOS hit this even before the spawn pin, spawn being its default; CI's
fork start method masked it). Rewrite to the same spawn-safe shape as
test_process_executor_runs_end_to_end: submit a pre-first-light year
(2016 < goes16 first light 2017-05-24) so every slice short-circuits
child-side via the available_since clamp with zero I/O, and assert the
skip actually held. Runs in ~2s with no network.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@helloiamvu helloiamvu merged commit a136631 into main Jul 5, 2026
19 checks passed
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