Skip to content

sdk-http-vertx: cap and expose MaxConcurrentStreams (default Integer.MAX_VALUE concentrates fan-in onto one event-loop) #615

Description

@tillrohrmann

Problem

RestateHttpServer.DEFAULT_OPTIONS configures HTTP/2 with no cap on concurrent streams:

private static final HttpServerOptions DEFAULT_OPTIONS =
    new HttpServerOptions()
        .setInitialSettings(new Http2Settings().setMaxConcurrentStreams(Integer.MAX_VALUE));

Vert.x pins each accepted HTTP/2 connection to one event-loop thread for the connection's lifetime, and all streams multiplexed on that connection serialize on that thread. Evidence in this codebase:

  • HttpEndpointRequestHandler extracts the per-connection context via ((HttpServerRequestInternal) request).context(), and the per-request executor re-enters that same context via ctx.runOnContext(runnable) (HttpEndpointRequestHandler.java:102-105). This guarantees every stream's state-machine syscalls run on the connection's pinned event loop.
  • Vert.x's standard HttpServer model (see Advanced Vert.x Guide — Threading) pins each accepted connection to a single event-loop context for its lifetime.

With MaxConcurrentStreams = Integer.MAX_VALUE a single HTTP/2 connection can multiplex arbitrarily many concurrent streams, all of which then serialize on one thread. Under load this concentrates fan-in rather than spreading it across the available event loops. Most other HTTP/2 server defaults are far smaller for this reason (Node's http2 default: 100; gRPC-Java default: ~100).

Proposal

  1. Lower the default setMaxConcurrentStreams(...) to a sensible value (e.g. 100, matching common HTTP/2 server defaults).
  2. Expose the knob on the endpoint builder so users who genuinely want unbounded multiplexing per connection can opt in.

The existing RestateHttpServer.from*(...) overloads already accept a user-supplied HttpServerOptions, so opting in to a higher cap is already possible — but most users won't pass custom options, and the current shipped default is the surprising one.

Files

  • sdk-http-vertx/src/main/java/dev/restate/sdk/http/vertx/RestateHttpServer.java (line 46-48 for DEFAULT_OPTIONS).

Context

Surfaced while investigating an intermittent InvokerMemoryTest failure in the Restate e2e suite. That specific failure had a different root cause (testcontainers' host-port relay), but the MaxConcurrentStreams=Integer.MAX_VALUE default came up repeatedly as a separate hardening item: nothing in the SDK protects users from a peer fanning N streams onto a single event-loop thread.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions