-
Notifications
You must be signed in to change notification settings - Fork 6
fix: Connection issues at high throughput #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,18 +26,24 @@ public class ModuleConfig : ICloudCodeSetup | |
|
|
||
| public void Setup(ICloudCodeConfig config) | ||
| { | ||
| config.Dependencies.AddScoped<IRequestAdapter>(_ => | ||
| config.Dependencies.AddSingleton<IRequestAdapter>(_ => | ||
| { | ||
| // TODO: Replace with required auth of your service | ||
| var authProvider = new AnonymousAuthenticationProvider(); | ||
|
|
||
| var handler = new HttpClientHandler | ||
| var handler = new SocketsHttpHandler | ||
| { | ||
| PooledConnectionLifetime = TimeSpan.FromMinutes(5), | ||
| PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2), | ||
| MaxConnectionsPerServer = 300, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| // TODO: Implement MTLS or other cert validation here | ||
| // ServerCertificateCustomValidationCallback = (_, _, _, _) => throw new NotImplementedException() | ||
| // SslOptions = new SslClientAuthenticationOptions { RemoteCertificateValidationCallback = (_, _, _, _) => throw new NotImplementedException() }, | ||
| }; | ||
|
|
||
| return new HttpClientRequestAdapter(authProvider, httpClient: new HttpClient(handler)) | ||
|
|
||
| // Cloud Code cancels an invocation at 15s; fail with budget left to return an error. | ||
| var httpClient = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(10) }; | ||
|
|
||
| return new HttpClientRequestAdapter(authProvider, httpClient: httpClient) | ||
| { | ||
| BaseUrl = AllocatorServiceBaseUrl | ||
| }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,8 +27,8 @@ | |
| { | ||
| public void Setup(ICloudCodeConfig config) | ||
| { | ||
| config.Dependencies.AddSingleton(GameApiClient.Create()); | ||
|
Check warning on line 30 in modules/EdgegapAllocator/Project/EdgegapAllocator.cs
|
||
| config.Dependencies.AddScoped<IEdgegapHttpClientFactory, EdgegapHttpClientFactory>(); | ||
| config.Dependencies.AddSingleton<IEdgegapHttpClientFactory, EdgegapHttpClientFactory>(); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -143,8 +143,8 @@ | |
| try | ||
| { | ||
| Secret edgegapApiToken = await gameApiClient.SecretManager.GetSecret(context, EdgegapApiTokenSecretName); | ||
| HttpClient client = httpClientFactory.Create(edgegapApiToken.Value); | ||
| HttpResponseMessage response = await client.GetAsync($"{EdgegapApiUrl}/v1/status/{requestId}"); | ||
| using HttpClient client = httpClientFactory.Create(edgegapApiToken.Value); | ||
| using HttpResponseMessage response = await client.GetAsync($"{EdgegapApiUrl}/v1/status/{requestId}"); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good — |
||
| string responseContent = await response.Content.ReadAsStringAsync(); | ||
|
|
||
| if (!response.IsSuccessStatusCode) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,8 +17,8 @@ | |
| { | ||
| public void Setup(ICloudCodeConfig config) | ||
| { | ||
| config.Dependencies.AddSingleton(GameApiClient.Create()); | ||
|
Check warning on line 20 in modules/RocketScienceAllocator/Project/RocketScienceAllocator.cs
|
||
| config.Dependencies.AddScoped<IRocketScienceHttpClientFactory, RocketScienceHttpClientFactory>(); | ||
| config.Dependencies.AddSingleton<IRocketScienceHttpClientFactory, RocketScienceHttpClientFactory>(); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -173,9 +173,21 @@ | |
|
|
||
| public class RocketScienceHttpClientFactory : IRocketScienceHttpClientFactory | ||
| { | ||
| // Static so the connection pool outlives a single invocation; a per-call handler re-handshakes every request. | ||
| private static readonly SocketsHttpHandler SharedHandler = new() | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Key assumption to validate: this only helps if the |
||
| { | ||
| PooledConnectionLifetime = TimeSpan.FromMinutes(5), | ||
| PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2), | ||
| MaxConnectionsPerServer = 300 | ||
| }; | ||
|
|
||
| public HttpClient Create(string apiKey) | ||
| { | ||
| var client = new HttpClient(); | ||
| // Cloud Code cancels an invocation at 15s; fail with budget left to return an error. | ||
| var client = new HttpClient(SharedHandler, disposeHandler: false) | ||
| { | ||
| Timeout = TimeSpan.FromSeconds(10) | ||
| }; | ||
| client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey); | ||
| return client; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consistency: here the handler is a non-static local captured by the singleton adapter (effectively singleton-scoped, default
disposeHandler: true), whereas Edgegap/Gameye/RocketScience use astatic readonly SharedHandlerwithdisposeHandler: false. Both work, but standardizing on one pattern makes it safer to copy into the remaining modules. Suggest thestatic readonlyform everywhere.Optional:
SocketsHttpHandlerdefaults to HTTP/1.1. If providers support h2,EnableMultipleHttp2Connections = truewould multiplex many requests over a few connections — a bigger win against connection exhaustion than raisingMaxConnectionsPerServer.