Skip to content

fix(python): stop teardown test flaking on unrelated thread reaps#2208

Open
claude[bot] wants to merge 1 commit into
mainfrom
claude/fix-teardown-thread-count-flake
Open

fix(python): stop teardown test flaking on unrelated thread reaps#2208
claude[bot] wants to merge 1 commit into
mainfrom
claude/fix-teardown-thread-count-flake

Conversation

@claude

@claude claude Bot commented Jul 26, 2026

Copy link
Copy Markdown

What changed

test_threads_joined_deterministically_after_drop no longer asserts an exact process-wide thread count. The check is now _assert_no_thread_growth(baseline) — one-directional, matching what the sibling test_fds_stable_across_tool_churn in the same file already did with <= baseline.

Two tests pin the direction: an inflated baseline must pass, growth must still fail.

Why

The test failed intermittently and blocked unrelated PRs — assert 13 == 14 on #2206, assert 15 == 16 on main at 082447e3 (a dependabot actions bump). Note the direction: the observed count was below the baseline. Nothing leaked; a thread went away.

The cause is tokio reaping idle blocking-pool threads on a 10 s timer. A pytest session that ran async work before this module sheds an unrelated thread part-way through the churn loop. Measured directly rather than guessed:

$ # sample /proc/self/task every 500ms for 20s after an async workload
thread-count transitions over 20s after an async workload:
  t= 0.0s  threads=6
  t=10.0s  threads=5      <- idle blocking-pool thread reaped

If baseline is captured inside that window, the reap lands mid-loop and exact equality reports a defect that did not occur.

TM-PY-030 is about what a drop leaves behind, and the process-wide count is not a single tool's to own. A genuine leak compounds across the five churn iterations and still pushes the count above the baseline, so leak detection is unchanged.

Before / After

The new tests discriminate — the same tests against the old == form vs. the fix:

# old (== baseline)
$ pytest test_teardown_determinism.py -k thread_check
1 failed, 1 passed, 6 deselected in 0.03s

# new (<= baseline)
$ pytest test_teardown_determinism.py -k thread_check
2 passed, 6 deselected in 0.02s

Full Python suite, four consecutive runs:

run 1: 742 passed, 2 skipped in 13.02s
run 2: 742 passed, 2 skipped in 13.45s
run 3: 742 passed, 2 skipped in 12.88s
run 4: 742 passed, 2 skipped in 12.33s

just pre-pr green, including cargo vet. ruff check and ruff format --check clean.

Risk

  • Low
  • Test-only change plus a knowledge note; no library, binding, or runtime code is touched.
  • The assertion is weaker in one direction by design. The direction it drops — a decrease in process-wide threads — cannot indicate a teardown defect, and the retained direction is the one TM-PY-030 cares about.
  • knowledge/python-package.md records the measurement and an explicit "do not re-tighten", so the equality check does not come back.

Checklist

  • Tests added or updated — two new tests pinning the invariant's direction, both verified to fail against the previous assertion
  • Backward compatibility considered — test-only; no public surface

Generated by Claude Code

test_threads_joined_deterministically_after_drop asserted an exact
process-wide thread count and failed intermittently in the shrink
direction (assert 13 == 14 here, assert 15 == 16 on main at 082447e),
blocking unrelated PRs.

Not a leak. tokio reaps idle blocking-pool threads on a 10 s timer, so a
pytest session that ran async work earlier sheds an unrelated thread
part-way through the churn loop. Measured: the count holds at 6 after an
async workload and drops to 5 at exactly t=10.0 s.

TM-PY-030 is about what a drop leaves behind, so the invariant is
one-directional. Replaces the equality check with
_assert_no_thread_growth(), matching what the sibling fd-churn test in
the same file already did. A real leak compounds across the five
iterations and still trips it.

Adds two tests pinning the direction: an inflated baseline must pass, and
growth must fail. Both fail against the old == form.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
bashkit 5ed0c54 Commit Preview URL

Branch Preview URL
Jul 26 2026, 05:40 AM

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