Commit dd5f00b
Tolerate Vert.x 5 pause/resume on ended requests (fixes silent test hangs) (#5383)
## Problem
The Vert.x 4 → 5 upgrade (80c5e37, 2026-06-10) changed
`HttpServerRequestImpl.pause()`/`fetch()`/`resume()` semantics: they now
`checkEnded()` and **throw** `IllegalStateException("Request has already
been read")` once the request body END event has been delivered. In
Vert.x 4 these calls were safe no-ops after end.
Tapir's vertx streaming bridge invokes `pause()`/`resume()` from
fire-and-forget fibers and Vert.x callbacks:
-
`server/vertx-server/cats/src/main/scala/sttp/tapir/server/vertx/cats/streams/fs2.scala`
— back-pressure loop in a started-and-never-joined fiber
-
`server/vertx-server/zio/src/main/scala/sttp/tapir/server/vertx/zio/streams/zio.scala`
— same pattern, `forkDaemon`-ed
-
`server/vertx-server/src/main/scala/sttp/tapir/server/vertx/streams/Pipe.scala`
— drain handlers / pipe start
-
`server/vertx-server/src/main/scala/sttp/tapir/server/vertx/handlers/package.scala`
— `streamPauseHandler` for every streaming/WS endpoint
Under CI load, a `pause`/`resume` racing the END event now throws,
silently killing the back-pressure fiber (or skipping cleanup such as
`socket.close()`), leaving stream consumers waiting forever. This is the
suspected root cause of the intermittent **silent hangs** in the vertx
cats/zio suites seen on dependency PRs #5373 / #5362, where CI went
quiet until the 15-minute retry timeout.
## Fix
Restore Vert.x 4 semantics at tapir's call sites by ignoring the
post-end `IllegalStateException`: after END there is nothing left to
pause/resume, so dropping the call is semantically correct. No
fibers/streams were restructured — only the pause/resume calls on the
request/read-stream are guarded (`.attempt.void` in fs2, `.ignore` in
zio, a small `ignoringReadEnded` helper in `Pipe.scala`, and a try/catch
in `streamPauseHandler`).
Companion PR: #5382 adds defensive timeouts + a thread-dump watchdog on
the CI side; this PR is the root-cause side.
## Verification
All variants compile (2.12 / 2.13 / 3): `vertxServer{,2_12,3}`,
`vertxServerCats{,2_12,3}`, `vertxServerZio{,2_12,3}`.
Test suites:
- `vertxServerCats2_12/test`: Tests: succeeded 292, failed 0 — all
passed
- `vertxServerZio3/test`: Tests: succeeded 295, failed 0 — all passed
- `vertxServer/test` (2.13): Tests: succeeded 554, failed 0 — all passed
Stress run of the formerly racy path — `vertxServerCats2_12/testOnly
sttp.tapir.server.vertx.cats.CatsVertxServerTest` 5 times in a loop: 5/5
passed (285 tests each).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>1 parent cbf3d49 commit dd5f00b
4 files changed
Lines changed: 18 additions & 8 deletions
File tree
- server/vertx-server
- cats/src/main/scala/sttp/tapir/server/vertx/cats/streams
- src/main/scala/sttp/tapir/server/vertx
- handlers
- streams
- zio/src/main/scala/sttp/tapir/server/vertx/zio/streams
Lines changed: 3 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
154 | 154 | | |
155 | 155 | | |
156 | 156 | | |
157 | | - | |
158 | | - | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
159 | 160 | | |
160 | 161 | | |
161 | 162 | | |
| |||
Lines changed: 3 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
24 | | - | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
25 | 27 | | |
26 | 28 | | |
27 | 29 | | |
| |||
Lines changed: 9 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
21 | 27 | | |
22 | 28 | | |
23 | 29 | | |
| |||
68 | 74 | | |
69 | 75 | | |
70 | 76 | | |
71 | | - | |
| 77 | + | |
72 | 78 | | |
73 | 79 | | |
74 | 80 | | |
| |||
116 | 122 | | |
117 | 123 | | |
118 | 124 | | |
119 | | - | |
| 125 | + | |
120 | 126 | | |
121 | 127 | | |
122 | 128 | | |
| |||
170 | 176 | | |
171 | 177 | | |
172 | 178 | | |
173 | | - | |
| 179 | + | |
174 | 180 | | |
175 | 181 | | |
176 | 182 | | |
Lines changed: 3 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
144 | 144 | | |
145 | 145 | | |
146 | 146 | | |
| 147 | + | |
147 | 148 | | |
148 | | - | |
| 149 | + | |
149 | 150 | | |
150 | | - | |
| 151 | + | |
151 | 152 | | |
152 | 153 | | |
153 | 154 | | |
| |||
0 commit comments