Skip to content

Update mockserver-netty to 7.4.0#5373

Merged
github-actions[bot] merged 3 commits into
masterfrom
update/mockserver-netty-7.4.0
Jul 7, 2026
Merged

Update mockserver-netty to 7.4.0#5373
github-actions[bot] merged 3 commits into
masterfrom
update/mockserver-netty-7.4.0

Conversation

@softwaremill-ci

Copy link
Copy Markdown
Contributor

About this PR

📦 Updates org.mock-server:mockserver-netty from 7.3.0 to 7.4.0

Usage

Please merge!

I'll automatically update this PR to resolve conflicts as long as you don't change it yourself.

If you'd like to skip this version, you can just close this PR. If you have any feedback, just mention me in the comments below.

Configure Scala Steward for your repository with a .scala-steward.conf file.

Have a fantastic day writing Scala!

⚙ Adjust future updates

Add this to your .scala-steward.conf file to ignore future updates of this dependency:

updates.ignore = [ { groupId = "org.mock-server", artifactId = "mockserver-netty" } ]

Or, add this to slow down future updates of this dependency:

dependencyOverrides = [{
  pullRequests = { frequency = "30 days" },
  dependency = { groupId = "org.mock-server", artifactId = "mockserver-netty" }
}]
labels: library-update, early-semver-minor, semver-spec-minor, commit-count:1

adamw added a commit that referenced this pull request Jul 7, 2026
…angs) (#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>
@github-actions github-actions Bot merged commit c1e7367 into master Jul 7, 2026
26 checks passed
@github-actions github-actions Bot deleted the update/mockserver-netty-7.4.0 branch July 7, 2026 12:28
adamw added a commit that referenced this pull request Jul 7, 2026
## Problem

The test `properly update metrics when a request times out` (in
`NettyFutureRequestTimeoutTests`, and its sync counterpart in
`NettySyncRequestTimeoutTests`) is flaky on CI, failing intermittently
with `1 was not equal to 0` at the `activeRequests.get() shouldBe 0`
assertion. It failed on three dependency-update PRs in the week of
2026-07-06 alone (runs for #5379, #5376 and #5373).

The root cause is a race in the test, not in production code: the
metrics are only decremented when the endpoint's logic completes, which
for the Future-based server happens ~1 second *after* the 503 timeout
response is received (the `Future` running the logic is not
interruptible). The test used a fixed `Thread.sleep(1100)`, leaving only
a ~100 ms margin before asserting — not enough on a loaded CI machine.
The sync test had an even tighter fixed `Thread.sleep(100)`.

## Fix

Replace the fixed sleeps with `eventually { ... }` and a widened
patience config (15 s timeout / 150 ms interval) — the same idiom
already used for the same reason in `ServerMetricsTest`. This asserts
eventual consistency instead of racing the asynchronous metrics update.
No production code is changed.

## Verification

Ran locally:
- `sbt "nettyServer/testOnly
sttp.tapir.server.netty.NettyFutureServerTest -- -z \"properly update
metrics\""` — passed
- `sbt "nettyServerSync3/testOnly
sttp.tapir.server.netty.sync.NettySyncServerTest -- -z \"properly update
metrics\""` — passed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
adamw added a commit that referenced this pull request Jul 7, 2026
)

## Problem

CI test runs intermittently hang: the build goes silent for ~9 minutes
until the 15-minute `nick-fields/retry` timeout kills sbt, and the
second attempt then frequently times out the same way, failing the job
after ~30 minutes. This was observed on dependency PRs #5373, #5362 and
#5376 during the week of 2026-06-27..2026-07-07. The suspected trigger
is the Vert.x 5 upgrade — a follow-up PR will address the Vert.x-side
cause; this PR makes the test infrastructure resilient and adds
diagnostics.

Two failure modes:

* **(A)** a single test hangs mid-suite (often the vertx cats/zio suites
— WebSocket/streaming waits with no timeout). Tests are not forked and
run one suite at a time, so one hung test stalls the entire run.
* **(B)** all tests pass, but `TestSuite.afterAll` blocks forever in an
unbounded `release.unsafeRunSync()` (e.g. a wedged `Vertx.close`), so
sbt never finishes.

## Changes

* **`DefaultCreateServerTest`**: each test's `IO` gets
`.timeout(3.minutes)` before `.unsafeToFuture()` — a hung test is
cancelled (running the server-close finalizer) instead of hanging the
suite.
* **`TestSuite` (JVM)**:
* every registered test is wrapped in a 4-minute safety-net timeout
(`IO.fromFuture(...).timeout(4.minutes)`), catching `Test`s constructed
outside `DefaultCreateServerTest`;
* suite resource acquisition (`tests.allocated`) is bounded to 2
minutes;
* `afterAll` bounds `release` and `shutdownDispatcher` to 1 minute each,
so a wedged backend close fails loudly instead of hanging the non-forked
sbt JVM forever.
* **`CatsVertxServerTest`**: the suite-level `vertx.close` wait is
bounded to 30 seconds; on timeout/failure it logs and continues.
* **CI workflow (JVM Test step only)**: a background watchdog checks
`output.log`'s mtime every 30 seconds; if the build has been silent for
>240 seconds it appends `jcmd <pid> Thread.print` dumps of all JVMs to
`thread-dumps.log`, which is uploaded as an artifact
(`if-no-files-found: ignore`). The sbt exit code and the existing `tee
output.log` + leak-grep behaviour are preserved.

## Verification

* `sbt "serverTests/Test/compile" "tests/Test/compile"` — compiles.
* `sbt "vertxServerCats2_12/testOnly
sttp.tapir.server.vertx.cats.CatsVertxServerTest"` — all 285 tests pass
through the new timeout wrappers and the bounded vertx close.
* `sbt "nettyServer/testOnly
sttp.tapir.server.netty.NettyFutureServerTest"` — 278/279 pass (incl.
the 5s graceful-shutdown and request-timeout metrics tests), confirming
the timeout wrappers don't regress longer-running tests. The single
failure (`bind(..) failed: Address already in use` in the leak test,
which uses the default port 8080) is environmental — running the same
suite on unmodified master on the same machine fails identically.
* `python3 -c "import yaml;
yaml.safe_load(open('.github/workflows/ci.yml'))"` — workflow YAML
valid.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
adamw added a commit that referenced this pull request Jul 7, 2026
)

## The leak

In `Http4sRequestBody`, the `RawBodyType.FileBody` case creates a temp
file via `serverOptions.createFile` and then compiles the body stream
into it. If the stream fails mid-write — e.g. with
`StreamMaxLengthExceededException` when the configured max content
length is exceeded (resulting in a 413) — the `RawValue(FileRange(file),
...)` is never produced. The interpreter's body-cleanup logic only
deletes files that were registered as raw values, so the temp file is
never deleted.

The leak happens on **every** over-limit file upload, making it a
disk-fill DoS vector: a client can fill the server's temp directory
simply by repeatedly sending oversized bodies to a file-body (or
multipart file) endpoint.

#5335 fixed exactly this in the akka, pekko, jdk-http, netty
(cats/future/sync/zio) and zio-http backends, but missed http4s.

## Why the shared test only catches it intermittently

The shared test `checks payload limit and returns 413 on exceeded max
content length (request)` (`ServerBasicTests`) polls for leftover temp
files containing the test's marker bytes. Whether the leaked file
contains those bytes depends on how the HTTP client chunks the request
and how much of the body was written before the limit interrupt — in
local runs the leaked file is often 0 bytes, so the marker check misses
it (and the oversized-request send may also end in the
`SttpClientException` recover path). The leak itself is deterministic;
only its detection is chunking-dependent. This is the source of the
flaky `Http4sServerTest` 413 failure seen e.g. on #5373's CI.

## The fix

Attach an `onError` handler to the stream compilation that deletes the
file via `serverOptions.deleteFile`. `onError` rethrows the original
error after running the handler, and the handler swallows its own
failures (`.attempt.void`) so a failing delete cannot mask the original
error. Since `toRawFromStream` is also used for multipart parts and by
the http4s-zio interpreter, those are covered too.

## Verification

- Baseline (unmodified master): `http4sServer/testOnly
sttp.tapir.server.http4s.Http4sServerTest -- -z 413` passes (5/5) but
leaves 1 leaked `/tmp/tapir*tmp` file (0 bytes — confirming why the
marker-based detection is intermittent).
- With the fix: the same 413 subset run 3 times — all green, 0 leaked
temp files after each run.
- `http4sServer2_12/compile`, `http4sServer3/compile`,
`http4sServerZio/compile`, `http4sServerZio3/compile` all succeed.
- Full `Http4sServerTest` suite: 302 tests, all passed, 0 leaked temp
files.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants