feat(harness): HTTP health polling on start (#3) #21
No reviewers
Labels
No labels
area:assertions
area:cli
area:client
area:harness
area:meta
area:reporting
area:runner
type:user-story
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/ws-rpc-test!21
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/3-health-polling"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #3.
Stacked on #20 (feat/2-harness-lifecycle).
Summary
Extends
ProcessHarness::start()with the HTTP health-poll loop. After the child is spawned, ifhealth_urlis set, the harness polls it until 2xx, the deadline elapses, or the child exits.What's in this PR
wait_for_health()private method invoked at the end ofstart(). Builds onereqwest::Clientperstart()call (not one per request).health_poll_interval(default 100 ms) until 2xx.stop(), returnsTestError::Connectionwith{url, last status, stderr tail}.TestError::Connectionwith{exit status, url, stderr tail}. A 50 ms drain delay before composing the error gives the background stdout/stderr reader tasks time to flush.health_urlisNone: silent no-op (start returns as soon as the child spawns).#[allow(dead_code)]fromstderr_tail()introduced in #2 — now actually used.Checklist (from issue #3)
health_urlvia reqwest GET athealth_poll_interval(default 100 ms)start()withOk(())startup_timeout: kills child, returnsTestError::Connectionwith URL + last HTTP status / transport error + stderr tailreqwest::Client(not one per request)Test plan
just qagreen locally — 20/20 unit tests pass (4 new in this PR)health_passes_when_endpoint_returns_200— in-process HTTP responder, success pathhealth_fails_on_timeout_when_no_listener— 1 s deadline, asserts URL + error wordinghealth_fails_when_child_exits_immediately— child writes to stderr then exits 7, asserts the captured stderr line appears in the errorhealth_check_skipped_when_no_url_set— health is optionalNotes for the reviewer
tokio::net::TcpListenerthat writes a literal HTTP/1.1 response. Avoids pulling in axum/warp/hyper just for test fixtures.reqwest::Client::builder().timeout(...)useshealth_poll_interval.max(1s)so we don't try to set a sub-1 s HTTP timeout (some reqwest versions panic on tiny timeouts).stop()call inside the timeout-error branch will issue another SIGTERM and reap; the early-exit branch already has the child reaped viatry_wait, so it just clearsself.child.Review — HTTP health polling on start (#3)
Concern : sleep de 50ms après exit du child
C'est un heuristique "laisse les tâches I/O se vider". Si le child produit beaucoup de sortie juste avant de crasher, 50ms peut ne pas suffire. Pour les usages tests courants ça passe, mais c'est fragile. Une approche plus robuste serait d'attendre la fermeture d'un channel que la tâche reader signale à l'EOF. À noter dans un commentaire au minimum.
Minor : ordre des vérifications dans la boucle
Le check
started.elapsed() >= startup_timeoutintervient après lesleep. Si la deadline expire exactement pendant le sleep, une requête HTTP supplémentaire part avant le timeout. Inoffensif mais le timeout n'est pas parfaitement serré.Ce qui est bien
reqwest::Clientpar appelstart()— correct (évite les handshakes TLS répétés).compose_health_errorinclut la queue stderr — excellent pour diagnostiquer les crashs au démarrage.max(health_poll_interval, 1s)comme timeout HTTP — évite des requêtes avec deadline absurde.Commentaires sans bloquant. Le sleep de 50ms après exit du child est le seul point un peu fragile, à documenter au minimum.