Skip to content

Vertx starts streaming buffer before onSuccess is completed #5825

@kvr000

Description

@kvr000

Version

5.0.5

Context

OS: Linux 6.17.0-6-generic #6-Ubuntu SMP PREEMPT_DYNAMIC Tue Oct 7 13:34:17 UTC 2025 x86_64 GNU/Linux (Kubuntu 25.10)
JVM: openjdk 21.0.9 2025-10-21

project link: https://github.com/kvr000/zbynek-java-exp/tree/master/http-exp/http-benchmark

In HttpClient streaming, Vertx seems to start pushing buffers prior to Future.onSuccess((HttpResponse) -> {}) is completed. As the stream handler is typically in that function, this results in loss of data:

In the github link, I provided benchmark, b3_VertxHttpClient is the randomly failing method - typically it misses about 2000 bytes - that indicates very close race condition.

In order to simulate bigger difference, I added sleep(1000) before registering onSuccess() callback and then it misses 1 GB.

Here is the additional snippet to the project:

	@Benchmark
	public void a0_VertxHttpClient(VertxHttpClientState state, Blackhole blackhole) throws Exception
	{
		MutableLong size = new MutableLong();
		Future<HttpClientResponse> future = state.httpClient.request(HttpMethod.GET, "/big_16GB")
			.compose(HttpClientRequest::send);
		Thread.sleep(1000);
		future.onSuccess((HttpClientResponse response) -> {
			if (response.statusCode() != 200) {
				Try.of(() -> { throw new IOException("Failed to retrieve file: status=" + response.statusCode()); }).get();
			}
			response.handler((buffer) -> size.add(buffer.length()));
		});
		future.await().end().await();
		if (future.await().statusCode() != 200) {
			throw new IllegalStateException("Unexpected status: " + future.await().statusCode());
		}
		if (size.longValue() != 16L*1024*1024*1024) {
			throw new IllegalStateException("Unexpected size: " + size);
		}
		blackhole.consume(size.longValue());
	}

Steps to reproduce

  1. Run the benchmark provided in the project.
  2. b3_VertxHttpClient will randomly fail with exception: java.io.IOException: Unexpected size: 17179865088

More reliable failure:

	@Benchmark
	public void a0_VertxHttpClient(VertxHttpClientState state, Blackhole blackhole) throws Exception
	{
		MutableLong size = new MutableLong();
		Future<HttpClientResponse> future = state.httpClient.request(HttpMethod.GET, "/big_16GB")
			.compose(HttpClientRequest::send);
		Thread.sleep(1000);
		future.onSuccess((HttpClientResponse response) -> {
			if (response.statusCode() != 200) {
				Try.of(() -> { throw new IOException("Failed to retrieve file: status=" + response.statusCode()); }).get();
			}
			response.handler((buffer) -> size.add(buffer.length()));
		});
		future.await().end().await();
		if (future.await().statusCode() != 200) {
			throw new IllegalStateException("Unexpected status: " + future.await().statusCode());
		}
		if (size.longValue() != 16L*1024*1024*1024) {
			throw new IllegalStateException("Unexpected size: " + size);
		}
		blackhole.consume(size.longValue());
	}

Do you have a reproducer?

https://github.com/kvr000/zbynek-java-exp/tree/master/http-exp/http-benchmark

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions