Repository navigation
[Fusion] Add an experimental YARP-style subgraph transport - #129
Open
michaelstaib wants to merge 3 commits into
Open
michaelstaib wants to merge 3 commits into
michaelstaib wants to merge 3 commits into
Conversation
The HotChocolate.Fusion.Experimental.SocketsHttpTransport AppContext switch makes Fusion send source schema requests through one SocketsHttpHandler per source schema that it owns, instead of through IHttpClientFactory. The handler does not store cookies or follow redirects, leaves automatic decompression at its default (off), uses a 15 s connect timeout and allows multiple HTTP/2 connections, and closes pooled connections after 2 minutes instead of rotating handlers. Shared clients never expire, and a schema reload keeps the handler of every source schema whose settings did not change. Gateway request headers named in the HotChocolate.Fusion.Experimental.SocketsHttpTransport.ForwardedHeaders AppContext data entry are copied from the HttpContext onto source schema requests, which replaces ASP.NET Core header propagation when the transport is on. The benchmark gateway opts in with BENCH_FUSION_SOCKETS_TRANSPORT=1.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
With the
HotChocolate.Fusion.Experimental.SocketsHttpTransportAppContext switch, Fusion sends source schema requests through oneSocketsHttpHandlerper source schema that it owns, with YARP's forwarding defaults (no cookies, no redirects, no decompression, 15 s connect timeout, pooled connections closed after 2 minutes instead of handler rotation), and copies the gateway request headers named in an AppContext data entry onto source schema requests itself instead of through ASP.NET Core header propagation. A schema reload keeps the handler of every source schema whose settings did not change, and requests without an execution deadline keep HttpClient's 100 s bound. This builds on upstream 4adcdf2 (the diff includes ChilliCream#10711 and ChilliCream#10712 until the fork's main catches up), so it measures only what goes beyond the invoker route of ChilliCream#10712: on the official benchmark with both inline settings, the transport keeps throughput, latency, CPU and RSS within run-to-run noise (about 1% req/s, 2% CPU) and removes about 0.7 KB of allocations per request. The switch keeps the default path unchanged, so this can land before a public configuration API exists.Official 16.7.0 subgraphs, alias-batching gateway configuration, k6 deep-recursion with 50 VUs, Kestrel
UnsafePreferInlineSchedulingandDOTNET_SYSTEM_NET_SOCKETS_INLINE_COMPLETIONS=1on for both sides. Medians of 4 (AOT constant-latency), 3 (AOT constant) and 2 (JIT) rounds; the first AOT variant rounds used a binary that still setAutomaticDecompressionexplicitly, which differs only in linked code. The benchmark gateway opts in withBENCH_FUSION_SOCKETS_TRANSPORT=1.Where the remaining transport cost is
JIT profile at constant latency (thread-time samples scaled to the measured 0.68 ms CPU per request, allocations from gc-verbose):
RedirectHandler). The transport removes all of it.SocketsHttpHandler: about 28% of CPU samples, including send and receive syscalls, and 6.9 KB per request (27% of all gateway allocations). That splits into header collections 2.4 KB,HttpConnection2.1 KB, pool and handler continuations 1.4 KB, and request/response messages with content 1.1 KB.HttpMessageInvokerwith these handler settings vs a raw-socket HTTP/1.1 floor) puts the most a Fusion-owned HTTP/1.1 client could still save at 3.7 to 3.8 µs per call on JIT and 5.5 to 6.7 µs per call on AOT, plus 1.8 KB per call. With 4 subgraph calls per request here, that is about 15 µs (JIT) or 23 µs (AOT) per request, 2 to 3% of gateway CPU, and about 7 KB of allocations per request.Configuration needs found by the prototype
The prototype ignores every
AddHttpClient("fusion")setting, so each of these needs a home in the configuration API:MaxConnectionsPerServer(the benchmark used 256),ConnectTimeout,PooledConnectionLifetime(DNS refresh, replaces handler rotation),PooledConnectionIdleTimeout,EnableMultipleHttp2Connections, HTTP/2 keep-alive pings. These settings also decide whether a schema reload keeps a handler.SslProtocols.VersionandVersionPolicy(HTTP/2 or h2c to source schemas). Today these come fromHttpClient.DefaultRequestVersion, which needsConfigureHttpClientand that turns off client sharing.AddRequestDeduplication, resilience handlers, logging. The prototype has no handler pipeline.AddHeaderPropagationoffers). The prototype reads a comma-separated list from AppContext.UseProxystays at its default, soHTTP_PROXY,HTTPS_PROXYandALL_PROXYstill reroute source schema calls. YARP turns it off and configures a proxy per cluster.AutomaticDecompressionas an opt-in. Setting it, even toNone, makes NativeAOT link the Brotli and Zstandard decoders (1.1 MB).TestServerby replacingIHttpClientFactory. The transport needs a way to supply the handler (like YARP'sIForwarderHttpClientFactory), andConnectCallbackwould cover Unix domain sockets to sidecars.ActivityHeadersPropagator, and theSystem.Net.Http.HttpClient.<name>log categories of IHttpClientFactory, which disappear.Open questions
UseProxy: keep the default (environment proxies apply) or turn it off like YARP.SendJsonAsync) adds a second send path, which would also need to call the header forwarder.