Support Multi<byte[]> as a streamed REST Client request body - #56465
Support Multi<byte[]> as a streamed REST Client request body#56465jnbdz wants to merge 1 commit into
Multi<byte[]> as a streamed REST Client request body#56465Conversation
This comment has been minimized.
This comment has been minimized.
|
🎊 PR Preview 24f4e67 has been successfully built and deployed to https://quarkus-pr-main-56465-preview.surge.sh/version/main/guides/
|
This comment has been minimized.
This comment has been minimized.
Multi<byte[]> as a streamed REST Client request body
geoand
left a comment
There was a problem hiding this comment.
Nice!
I will also what I've also asked for in other similar PRs: The test should be updated to use Multi that does not fit in memory, thus ensuring that no buffering is happening
This comment has been minimized.
This comment has been minimized.
b9c2037 to
90109a0
Compare
|
Done in 90109a0d3c1: |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
geoand
left a comment
There was a problem hiding this comment.
The SendMultiBytesTest failure in the Semeru run is very suspicious. We really need to understand what's going on
The REST Client already streams a `Multi<io.vertx.core.buffer.Buffer>` body without buffering it, but this was the only accepted `Multi` item type, so a `Multi<byte[]>` produced by another client call (or by any byte-oriented source) had to be converted by the caller. Accept `Multi<byte[]>` in the build-time check and convert items to `Buffer` when the body is sent. A downloaded `Multi<byte[]>` can now be passed straight to another client method as the request body. A `Multi` body that fails part-way used to be reported as a success: `HttpClientRequest.send(ReadStream)` pipes the stream with the default `endOnFailure(true)`, and the Mutiny `ReadStreamSubscriber` invokes the end handler after the exception handler, so the chunked body was ended normally and the server response to the truncated body was returned to the caller. Pipe the stream explicitly with `endOnFailure(false)` and reset the request with the source failure, as the multipart path already does, so the call fails with a `ProcessingException`. The documentation listed `Multi<io.vertx.mutiny.core.buffer.Buffer>`, a type that no longer exists with the Vert.x 5 Mutiny bindings; it is replaced by the two types that are actually accepted. Relates to quarkusio#21440
90109a0 to
0c3abc9
Compare
|
Agreed, it was a real bug, and it is on the request side, not in the test. What happened on Semeru: the download Fixed in 0c3abc9f3b4: the The 2 GB pipe test itself stays. Whether it passes on Semeru also depends on the download side not filling the heap, so it is worth a run once #56462 is in as well. |
Status for workflow
|
This comment has been minimized.
This comment has been minimized.
| // a failing Multi must fail the request: with the default pipe behaviour the body would be ended | ||
| // normally and the server response to the truncated body would be reported as a success | ||
| ReadStream<Buffer> body = ReadStreamSubscriber.asReadStream(buffers, | ||
| new Function<>() { | ||
| @Override | ||
| public Buffer apply(Buffer buffer) { | ||
| return buffer; | ||
| } | ||
| })); | ||
| }); | ||
| Pipe<Buffer> pipe = body.pipe(); | ||
| pipe.endOnFailure(false); | ||
| pipe.to(httpClientRequest).onComplete(new Handler<>() { | ||
| @Override | ||
| public void handle(AsyncResult<Void> ar) { | ||
| if (ar.failed()) { | ||
| httpClientRequest.reset(0L, ar.cause()); | ||
| } | ||
| } | ||
| }); | ||
| Future<HttpClientResponse> sent = httpClientRequest.response(); |
There was a problem hiding this comment.
I think the piping here is correct
Status for workflow
|
| Status | Name | Step | Failures | Logs | Raw logs | Build scan |
|---|---|---|---|---|---|---|
| ✔️ | JVM Tests - JDK 21 | Logs | Raw logs | 🚧 | ||
| ✔️ | JVM Tests - JDK 25 | Logs | Raw logs | 🚧 | ||
| ✔️ | JVM Tests - JDK 25 Semeru | Logs | Raw logs | 🚧 | ||
| ❌ | JVM Tests - JDK 21 Windows | Build |
Failures | Logs | Raw logs | 🔍 |
You can consult the Develocity build scans.
Failures
⚙️ JVM Tests - JDK 21 Windows #
- Failing: extensions/resteasy-reactive/rest-client/deployment
! Skipped: extensions/keycloak-admin-rest-client/deployment extensions/liquibase/liquibase-mongodb/deployment extensions/micrometer-opentelemetry/deployment and 19 more📦 extensions/resteasy-reactive/rest-client/deployment
❌ Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:3.5.6:test (default-test) on project quarkus-rest-client-deployment: There was a timeout in the fork

The REST Client streams a
Multi<io.vertx.core.buffer.Buffer>request body without buffering it, but that is the onlyMultiitem type accepted by the build-time check inJaxrsClientReactiveProcessor. AMulti<byte[]>(for example the one returned by another client method declared with that return type) is rejected withWhen using Multi as body parameter only Multi<io.vertx.core.buffer.Buffer> is supported, so the caller has to map it toBufferfirst.This PR accepts
Multi<byte[]>as well:Multi<byte[]>next toMulti<Buffer>;ClientSendRequestHandlerconverts each item to aBufferbefore handing the stream to Vert.x, soBufferitems pass through unchanged andbyte[]items are wrapped. Programmatic clients (Entity.entity(multi, ...)) have no build-time check, so an unsupported item type now fails the request with a clear message instead of aClassCastException;Multibody that fails part-way is now reported as a failure.HttpClientRequest.send(ReadStream)pipes with the defaultendOnFailure(true)and the MutinyReadStreamSubscriberinvokes the end handler after the exception handler, so the chunked body was ended normally and the server response to the truncated body was returned as a success. The stream is now piped withendOnFailure(false)and the request is reset with the source failure, as the multipart path already does, so the call fails with aProcessingException;Multi<io.vertx.mutiny.core.buffer.Buffer>, a type that no longer exists with the Vert.x 5 Mutiny bindings. It now lists the two accepted types.Relates to #21440 (request side; the response side is #56462).