Skip to content

perf(tests): stop paying the 0.5s serve_forever poll on every teardown - #1078

Draft
seonghobae wants to merge 3 commits into
mainfrom
perf/test-suite-serve-forever-poll
Draft

perf(tests): stop paying the 0.5s serve_forever poll on every teardown#1078
seonghobae wants to merge 3 commits into
mainfrom
perf/test-suite-serve-forever-poll

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Outcome

The pytest suite spends a material amount of wall time waiting for throwaway socketserver.BaseServer instances to notice shutdown(). Test fixtures start hundreds of http.server instances with serve_forever() and therefore inherit its 0.5-second polling default. This PR changes only the pytest process: root conftest.py preserves the production call sites while wrapping BaseServer.serve_forever with a 0.01-second default poll interval.

The performance claim is deliberately scoped to test execution. Back-to-back local measurements on the predecessor implementation tree retained the same collected/passed count (3395 passed, 1 skipped) while wall time moved from 652.57 s to 46.68 s; patched repeats were 46.68 s, 72.08 s, and 83.98 s. These local runs support the shutdown-poll mechanism but are not production latency, API p95, or hosted-runner evidence.

Review → RED → causal GREEN

Fresh fleet review found that the test-only global override had no executable contract of its own. The PR was moved to Draft before repair.

Normal descendant c045c79b0221d4f58f8231a8be2c35c00762d077 adds tests/test_test_server_poll_interval.py and keeps the implementation unchanged. The regression proves:

  • a no-argument test serve_forever() call is delegated to the original method with poll_interval=0.01;
  • an explicit caller-supplied interval such as 0.25 is preserved instead of overwritten;
  • the class-level override installed for pytest is the wrapper under test.

An isolated exact-file run on this descendant is 2 passed in 0.07s. This is focused local evidence only, not protected/hosted GREEN.

Exact authority

  • protected base: main@a080297d2546bb61e89520d637cabc202db331ec
  • exact head: c045c79b0221d4f58f8231a8be2c35c00762d077
  • ancestry: ahead 2 / behind 0; merge base is the protected base
  • effective files: conftest.py, tests/test_test_server_poll_interval.py
  • production source, provider routing, dependencies, workflows, release semantics: unchanged

The branch was returned to Ready only to materialize fresh exact-head review/check evidence. Current exact-head Security and Quality 33959628627, Security Scan 33959628647, SAST Semgrep 33959628620, and CodeQL PR 33959628663 are queued. Earlier measurements and predecessor workflow runs do not transfer as merge acceptance.

Promotion boundary

Before normal protected merge, require the unchanged exact head to satisfy all live required contexts, current review/thread requirements, and independent approval. If hosted execution exposes test-order leakage, third-party server incompatibility, or materially different test counts, repair this same descendant rather than weakening the gate. No source-neutral retrigger, self-approval, bypass, force-push, destructive rebase, or predecessor-evidence transfer.

Summary by CodeRabbit

  • 버그 수정

    • 테스트 환경에서 임시 서버가 종료될 때 불필요하게 오래 대기하던 문제가 개선되었습니다.
    • 서버 종료 처리가 더 빠르고 안정적으로 완료됩니다.
  • 테스트

    • 서버 폴링 간격의 기본 동작과 명시적으로 설정한 간격이 유지되는지 검증하는 회귀 테스트가 추가되었습니다.

The suite stands hundreds of throwaway http.server instances in for provider
endpoints, all started as threading.Thread(target=server.serve_forever). The
stop flag is only checked once per poll_interval, and shutdown() blocks until
that check, so every teardown pays up to the 0.5s default. All 326 call sites
under tests/ use the default; none passes the argument.

Overriding the default in the root conftest takes the full suite from 652.57s
to 46.68s with an identical 3395 passed / 1 skipped, measured back to back on
one tree. Repeat patched runs land between 47s and 84s depending on machine
load, so the honest range is roughly 8-14x.

The override goes in conftest rather than the call sites because
tests/test_telemetry.py pins production serve() to calling serve_forever()
with no arguments, and because it is one file instead of 233.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 0e27bed7-cc77-43d5-9c9a-e0cc0abd88a8

📥 Commits

Reviewing files that changed from the base of the PR and between 89081ad and 917d53e.

📒 Files selected for processing (1)
  • tests/test_test_server_poll_interval.py

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

테스트 설정이 socketserver.BaseServer.serve_forever를 패치합니다. 기본 poll_interval을 0.01초로 설정하고, 명시적 간격을 유지하는 동작을 회귀 테스트로 검증합니다. 패치의 전역 적용 이유를 모듈 문서에 기록합니다.

Changes

테스트 서버 종료 동작

Layer / File(s) Summary
serve_forever 폴링 간격 패치 및 검증
conftest.py, tests/test_test_server_poll_interval.py
기존 serve_forever를 저장한 뒤 기본 poll_interval이 0.01초인 래퍼를 socketserver.BaseServer에 적용합니다. 명시적 poll_interval 보존과 반환값 전달을 테스트합니다. 모듈 문서는 전역 적용 이유와 종료 동작을 설명합니다.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 917d5

This change shortens test-server shutdown waits during pytest while retaining explicitly requested polling intervals. No current merge-blocking risk is identified.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 테스트 종료 시 serve_forever의 0.5초 폴링 대기를 줄이는 핵심 변경을 정확하게 설명합니다. 간결하고 구체적이며 변경 내용과 직접 관련됩니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/test-suite-serve-forever-poll

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@seonghobae
seonghobae marked this pull request as draft September 5, 2026 10:03

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fresh fleet review found the performance shim had no executable contract of its own. I moved the PR to Draft, added tests/test_test_server_poll_interval.py, and kept the repair limited to pytest-only infrastructure. Exact head is now c045c79b0221d4f58f8231a8be2c35c00762d077, directly ahead of protected main@a080297d2546bb61e89520d637cabc202db331ec by two commits / behind 0; effective delta is only conftest.py plus the new regression. The regression proves the no-argument test path is translated to poll_interval=0.01, an explicit caller-supplied interval remains unchanged, and the class-level test override is the wrapper under test. An isolated exact-file pytest execution is 2 passed in 0.07s; this is not hosted/protected GREEN. No production server path, provider routing, workflow, dependency, or release semantics are changed. Re-promote only to materialize fresh exact-head gates; do not transfer the predecessor queued runs or the earlier wall-clock observations as acceptance evidence.

@seonghobae

Copy link
Copy Markdown
Contributor Author

독립 로컬 검증 + 후속 측정 (autoresearch)

이 PR의 주장("약 11분 → 약 1분")을 이 PR을 읽기 전에 설정한 계측으로 재현했습니다. 같은 명령(pytest tests -q -p no:randomly), 같은 머신, 실행 간 겹침 없이 직렬로.

exp  commit   metric(s)  status    변경
0    a080297  689.72     baseline  CO main 그대로 (3394 passed)
1    c045c79   54.76     keep      이 PR (#1078) 적용  → 12.6×
2    39f983a   47.26     keep      poll 0.01 → 0.001 추가  → 추가 −7.5s (−13.7%)

12.6×, 3396 passed — 주장 재현됩니다. 통과 수가 2개 늘어난 건 이 PR의 계약 테스트입니다.

serve_forever 패치가 정확히 그 레버인지 — 호출별 실측

cProfile 평균은 이 질문에 세 번 오답을 냈습니다(shutdown 129ms/call, 임베딩 close 21ms, urlopen 70ms — 전부 워밍업 왜곡). perf_counter 래퍼로 호출마다 찍으니:

base.shutdown  [10.3, 10.8, 9.3, 0.0] ms   ← poll_interval 그대로
close_embed    [ 0.1, 0.0, 0.0, 0.0] ms   ← 없음
urlopen        [209.1, 2.0, 1.5, 1.1] ms  ← 첫 호출만 워밍업, 이후 1.5ms
build_server                     ~3 ms

shutdown()serve_foreverpoll_interval 한 번을 정확히 기다립니다. 이 리포는 342개 테스트 파일 중 **179개가 *_http_honesty.py**이고 각각 로컬 _server()로 서버를 세워(build_server 호출 984 + 205) 테스트마다 부수므로, 그 poll이 ~1,056번 곱해집니다. 이 PR의 BaseServer 몽키패치가 옳은 지점인 이유는 ResponsiveThreadingHTTPServerserve_forever오버라이드하지 않기 때문입니다 — 확인했습니다(shutdown/server_close만 오버라이드하고, 둘 다 super를 부릅니다).

후속 제안: 0.010.001

exp2가 그것입니다. 남은 poll 10ms/test를 1ms로 줄여 −7.5s. 이 PR의 계약 테스트가 0.01을 핀하고 있어(tests/test_test_server_poll_interval.py:20) 그 줄도 같이 바꿔야 합니다. 두 파일 두 줄입니다. 별도 PR로 경쟁시키지 않고 여기 남깁니다 — 이 PR에 흡수하시든, 후속으로 두시든 소유자 판단입니다.

그 다음은 없습니다 (플래토)

exp2 위에서 --durations=30을 돌렸습니다. 상위 30개에 http_honesty가 0개 — 서버 비용은 완전히 노이즈 아래입니다. 상위 30 합이 47s 중 12.8s이고 전부 ① Hypothesis fuzz(max_examples를 줄이면 테스트가 약해짐) ② 의도된 timeout 테스트 ③ 실제 연산입니다. 나머지 ~34s는 3,366개 테스트 × ~10ms 잔여 오버헤드(build_server 3 + bind 2 + urlopen 1.5 + thread)라 conftest 수준 레버가 없습니다. 3,396개에 47s면 테스트당 14ms입니다.

사람이 볼 만한 것 하나: test_model_discovery*0.50~0.51s로 균일한 테스트가 4개 있습니다. 재시도 backoff sleep 냄새가 납니다. 프로덕션 타이밍 의미가 걸려 있어 자동 실험에서는 뺐습니다.

계측·결과·브랜치는 로컬(autoresearch/sep05-co-suite, 이 PR 위 1커밋)이고 push하지 않았습니다.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Merged origin/main at 414f2297 into this branch → head 917d53e1 (clean, no conflicts; diff against main is still exactly conftest.py plus the polling contract test).

Why a push and not a code fix: all six failing checks were created 2026-09-05T10:03Z by the previous head, and none is caused by this PR's change:

check first ##[error] cause
opencode-review "No APPROVED or CHANGES_REQUESTED from opencode-agent on the current head" review dispatch rejected at the dispatcher allowlist — ContextualWisdomLab/.github#1929
CodeQL compatibility analysis ×3 "CodeQL scan dispatched … will rerun after publishing its terminal verdict" same allowlist; no terminal verdict ever returns — ContextualWisdomLab/.github#1925 / #1929
strix "provider/backend was unavailable" pre-#1939 NVIDIA-only sidecar pool
noema-review "HTTP 502 … duration=1508.0s" same sidecar stall, 25 min held

Required runs bind workflow_sha at creation, so a re-run would execute the pre-#1939 sidecar; only a new event binds the current one. This push is that event.

What it will and will not change: strix and noema-review can now go green. opencode-review and the three CodeQL contexts will fail again at the allowlist until OPENCODE_REPOSITORY_DISPATCH_ACTOR is updated (#1929). And this PR stays unmergeable regardless: main protection still requires four contexts nothing produces since #1054 (#1079).

Gates on 917d53e1: 3398 passed, 1 skipped in 77.70s (the suite this PR speeds up); interrogate 100%.

@seonghobae

Copy link
Copy Markdown
Contributor Author

The three CodeQL compatibility analysis contexts on 917d53e1: no PR-side fix, and I am not pushing.

All three fail on run 34017966465 (created 07:00Z) with the same closed-failure — CodeQL scan dispatched. The dispatch workflow will rerun this exact failed CodeQL job after publishing its terminal verdict. Detect CodeQL languages succeeded, and this repository's own CodeQL, supply chain, and SBOM job succeeded on the same head. The dispatched scan never publishes a verdict because codeql-scan-dispatch is rejected at the dispatcher allowlist; that was live-confirmed minutes ago on run 34018067448 — created after the allowlist variable was touched at 07:01Z — which still failed step 3 with authorization rejected actor=opencode-agent[bot] (ContextualWisdomLab/.github#1929).

Two things worth being precise about:

@seonghobae

Copy link
Copy Markdown
Contributor Author

strix on 917d53e1: no PR-side fix, and I am not pushing. It failed at step 16 (provisioning the review sidecar) because every preflight route across all three provider accounts returned HTTP 429 — the per-account skip lever fired, nothing was left to serve, and the sidecar exited before healthz. That is upstream rate-limiting at preflight (capacity), not anything in conftest.py, and not the sandbox-bootstrap class that #1953 fixes — so a push to rebind a post-#1953 sidecar would just re-roll the same 429s at queue cost. Full log reading is on ContextualWisdomLab/.github#1939.

@seonghobae

Copy link
Copy Markdown
Contributor Author

noema-review on 917d53e1: ①-no-tools, no PR-side fix, not pushing. Preflight confirmed after 394s, the walk ran across nvidia_nim/nvidia_nim_sub routes, and the gateway returned 502 after 1077.2s. Gateway capacity, not conftest.py. opencode-review on the same head is the dispatcher-allowlist rejection (ContextualWisdomLab/.github#1929), also unfixable here. Full reading on ContextualWisdomLab/.github#1939.

@seonghobae seonghobae added priority: medium Normal-priority or P2 work status: needs-review Open pull request requiring current-head review or checks type: maintenance Maintenance, build, dependency, or operational upkeep maintenance labels Sep 7, 2026 — with ChatGPT Codex Connector
@seonghobae

Copy link
Copy Markdown
Contributor Author

All five failing checks are upstream of this pull request; none is a finding about the change, and nothing was pushed.

The durations separate them before any log is read:

CodeQL compatibility analysis (actions)               5s
CodeQL compatibility analysis (javascript-typescript) 4s
CodeQL compatibility analysis (python)                4s
opencode-review                                       8s
noema-review                                        964s

The four fast ones are half a handshake. These jobs dispatch their work and fail deliberately in seconds to release the runner, expecting to be rerun once a verdict is published. Their annotations say so:

CodeQL:          CodeQL scan dispatch or exact-head verdict read did not succeed (outcome=failure)
opencode-review: No APPROVED or CHANGES_REQUESTED from opencode-agent on the current head.
                 The dispatch workflow will rerun this failed job after publishing an
                 authenticated exact-head verdict.

The verdict never arrives because the central dispatch is rejected at its identity allowlist — ContextualWisdomLab/.github#1929, where the actor is opencode-agent[bot] and the configured value is github-actions[bot]. No change here affects that.

The slow one is a gateway transport failure, not a review. noema-review failed at step 13 Prepare Noema model verdict:

Noema gateway transport failed: HTTPError: HTTP Error 502: Bad Gateway;
  caller attempts=1, duration=88.1s, phase=response_error, served_model=unknown

served_model=unknown and a 502 mean the request never reached a model — this is the same upstream class recorded on .github#1939, not a judgement about conftest.py.

Independent of all of the above

This pull request cannot merge regardless, and for a different reason again: main's branch protection still requires four contexts that no workflow produces after #1054 renamed the jobs (Hypothesis property tests, Atheris coverage-guided, CodeQL analysis, Python supply chain). That is tracked in #1079 and is an owner decision, since branch protection is an authorization boundary.

So there are three separate causes stacked here, and none of them is in the diff — which remains conftest.py plus its test.

One thing worth recording

The scope-gating behaviour documented for .github holds here too, in a repository where the central workflows run in this repo's context: this branch changes .py files, the CodeQL scope gate therefore opens, and the checks go red rather than passing vacuously. A documentation-only branch in the same organization showed those same jobs green in 2 s because the gate stayed shut. Red CodeQL here is evidence the gate opened, not evidence about the code.

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

OpenCode reviewed the current-head product diff. Coverage is a separate gate.

Changed files

  • conftest.py — Python module behavior
  • tests/test_test_server_poll_interval.py — regression suite

Changed behavior

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Python: conftest.py"]
  S1 --> I1["Python module behavior"]
  I1 --> R1["Review risk: Python: conftest.py"]
  R1 --> V1["pytest plus coverage"]
  Evidence --> S2["Test: test_test_server_poll_interval.py"]
  S2 --> I2["regression suite"]
  I2 --> R2["Review risk: Test: test_test_server_poll_interval.py"]
  R2 --> V2["targeted test run"]
Loading

Findings

No source-backed product finding is synthesized from the coverage gate. A coverage miss belongs in the status comment.

  • Head SHA: 917d53e1541432787879ff32573eaa51dbe09017
  • Workflow run: 34078358514
  • Workflow attempt: 1
  • Coverage gate: failure

Review outcome

Coverage is a gate, not the review. This body reviews the changed product files.

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Python: conftest.py"]
  S1 --> I1["Python module behavior"]
  I1 --> R1["Review risk: Python: conftest.py"]
  R1 --> V1["pytest plus coverage"]
  Evidence --> S2["Test: test_test_server_poll_interval.py"]
  S2 --> I2["regression suite"]
  I2 --> R2["Review risk: Test: test_test_server_poll_interval.py"]
  R2 --> V2["targeted test run"]
Loading

@opencode-agent

opencode-agent Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

OpenCode Review Overview

Coverage evidence did not pass, so approval is blocked. The formal pull-request review is the source-backed diff review, not this status comment.

@seonghobae

Copy link
Copy Markdown
Contributor Author

COVERAGE_BLOCKED here means coverage could not be measured, not that it is insufficient — and the cause is in the base lock, not in this diff.

OpenCode did run and publish a formal review this time, with no product findings; the block comes entirely from the coverage gate. Following it to the actual failure:

.github run 34078358514  ->  job coverage-evidence
  8. success   Enforce changed-file syntax gate
  9. FAILURE   Measure test and docstring evidence
 10. success   Complete job

annotation: Could not materialize base Python locks: uv export for tracked base lock
            uv.lock was not fully hash-pinned or exact organization VCS-pinned

Step 9 never reached a coverage number. It failed while materializing the base Python environment.

Why this is not the diff

This branch changes exactly two files, neither of them a dependency manifest:

modified  conftest.py
added     tests/test_test_server_poll_interval.py

And the lock it complains about is almost entirely pinned already. Parsing uv.lock on main:

packages                      58
sha256 hash entries         1177
packages with no hash          1   ->  contextual-orchestrator, source = { virtual = "." }

The single unhashed entry is the project's own virtual root, which cannot carry a hash by construction — it is the local package, not a fetched dependency. So the condition the gate objects to is a property of main's lock file, present before this branch existed and unaffected by anything in it.

I am reading that virtual root as the likely trigger rather than asserting it: the message allows two acceptable forms ("fully hash-pinned or exact organization VCS-pinned"), and whether a virtual root is meant to be exempted is a question for whoever owns that gate. What is not in question is that no change to conftest.py or a test file can alter it.

Practical consequence

Any pull request in this repository reviewed through this path will reach the same block, because the input it fails on is the base lock rather than the PR. That makes COVERAGE_BLOCKED uninformative about the change under review here — worth knowing before anyone treats it as a signal about the diff.

Note on the run id in the review body

The review cites Workflow run: 34078358514, which 404s in this repository. The central OpenCode workflow executes in ContextualWisdomLab/.github and dispatches into this repository's context, so that id resolves there, not here. Anyone checking the evidence should look it up in .github.

Two coverage results also exist for this same head, from different runs, and they disagree:

this repo, run 34017964985   2026-09-06 07:00   coverage-evidence  success
.github,   run 34078358514   2026-09-07 03:04   coverage-evidence  failure

The dispatch run is the newer one and is what the verdict reflects.

Nothing pushed; the diff remains conftest.py plus its regression test.

@seonghobae
seonghobae marked this pull request as draft September 8, 2026 08:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintenance priority: medium Normal-priority or P2 work status: needs-review Open pull request requiring current-head review or checks type: maintenance Maintenance, build, dependency, or operational upkeep

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant