From 5a7f1b550139455d3c381abc8acc6b17a2e0e810 Mon Sep 17 00:00:00 2001 From: Yun Wang Date: Thu, 1 Oct 2026 14:09:57 +0200 Subject: [PATCH] perf: raise the default connection pool size from 5 to 100 The default of 5 capped each client at 5 concurrent requests, so busy servers queued behind the pool. 100 matches httpx's default and stream-py. --- src/ClientBuilder.cs | 4 ++-- src/StreamOptions.cs | 6 +++--- tests/ClientBuilderTests.cs | 4 ++-- tests/ConnectionPoolTests.cs | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/ClientBuilder.cs b/src/ClientBuilder.cs index f434f88..b7c9631 100644 --- a/src/ClientBuilder.cs +++ b/src/ClientBuilder.cs @@ -31,7 +31,7 @@ public class ClientBuilder private bool _loadEnv = true; private string? _envPath; private string? _envFilePath; - private int _maxConnsPerHost = 5; + private int _maxConnsPerHost = 100; private TimeSpan _idleTimeout = TimeSpan.FromSeconds(55); private TimeSpan _connectTimeout = TimeSpan.FromSeconds(10); private TimeSpan _requestTimeout = TimeSpan.FromSeconds(30); @@ -85,7 +85,7 @@ public ClientBuilder EnvPath(string path) return this; } - /// CHA-2956: max concurrent TCP connections per host (default 5). + /// CHA-2956: max concurrent TCP connections per host (default 100). public ClientBuilder MaxConnsPerHost(int n) { _maxConnsPerHost = n; return this; } /// CHA-2956: how long an idle pooled connection lingers (default 55s). diff --git a/src/StreamOptions.cs b/src/StreamOptions.cs index 3dde480..4f74b7a 100644 --- a/src/StreamOptions.cs +++ b/src/StreamOptions.cs @@ -7,7 +7,7 @@ namespace GetStream /// /// Configuration object for covering credentials, base URL, HTTP connection-pool tuning (CHA-2956), and optional dependencies. /// - /// Defaults: MaxConnsPerHost=5, IdleTimeout=55s, ConnectTimeout=10s, RequestTimeout=30s. + /// Defaults: MaxConnsPerHost=100, IdleTimeout=55s, ConnectTimeout=10s, RequestTimeout=30s. /// KeepAlive is always-on; the SDK never emits Connection: close. /// public class StreamOptions @@ -21,8 +21,8 @@ public class StreamOptions /// Base URL. Default https://chat.stream-io-api.com. public string BaseUrl { get; set; } = "https://chat.stream-io-api.com"; - /// Max concurrent TCP connections per host. Default 5. - public int MaxConnsPerHost { get; set; } = 5; + /// Max concurrent TCP connections per host; extra requests wait for a free connection. Default 100. + public int MaxConnsPerHost { get; set; } = 100; /// How long an idle pooled connection lingers. Default 55s (5s below the typical 60s LB idle timeout). public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromSeconds(55); diff --git a/tests/ClientBuilderTests.cs b/tests/ClientBuilderTests.cs index feba5fe..39a24dd 100644 --- a/tests/ClientBuilderTests.cs +++ b/tests/ClientBuilderTests.cs @@ -158,7 +158,7 @@ public void ClientBuilder_DefaultsWhenNoPoolKnobsSet() .SkipEnvLoad() .BuildChatClient(); var (httpClient, handler) = GetStream.Tests.ConnectionPoolTests.UnwrapWrapperHandler(chatClient); - Assert.That(handler.MaxConnectionsPerServer, Is.EqualTo(5)); + Assert.That(handler.MaxConnectionsPerServer, Is.EqualTo(100)); Assert.That(handler.PooledConnectionIdleTimeout, Is.EqualTo(TimeSpan.FromSeconds(55))); Assert.That(handler.ConnectTimeout, Is.EqualTo(TimeSpan.FromSeconds(10))); Assert.That(httpClient.Timeout, Is.EqualTo(TimeSpan.FromSeconds(30))); @@ -196,7 +196,7 @@ public void Build_StreamClient_DefaultsWhenNoPoolKnobsSet() .SkipEnvLoad() .Build(); var (httpClient, handler) = GetStream.Tests.ConnectionPoolTests.UnwrapHandler(client); - Assert.That(handler.MaxConnectionsPerServer, Is.EqualTo(5)); + Assert.That(handler.MaxConnectionsPerServer, Is.EqualTo(100)); Assert.That(handler.PooledConnectionIdleTimeout, Is.EqualTo(TimeSpan.FromSeconds(55))); Assert.That(handler.ConnectTimeout, Is.EqualTo(TimeSpan.FromSeconds(10))); Assert.That(httpClient.Timeout, Is.EqualTo(TimeSpan.FromSeconds(30))); diff --git a/tests/ConnectionPoolTests.cs b/tests/ConnectionPoolTests.cs index 9c084ff..3977894 100644 --- a/tests/ConnectionPoolTests.cs +++ b/tests/ConnectionPoolTests.cs @@ -27,8 +27,8 @@ public void BaseClient_WithDefaultStreamOptions_HasSpecDefaults() var (httpClient, handler) = UnwrapHandler(client); Assert.That(httpClient.Timeout, Is.EqualTo(TimeSpan.FromSeconds(30)), "default RequestTimeout = 30s"); - Assert.That(handler.MaxConnectionsPerServer, Is.EqualTo(5), - "default MaxConnsPerHost = 5"); + Assert.That(handler.MaxConnectionsPerServer, Is.EqualTo(100), + "default MaxConnsPerHost = 100"); Assert.That(handler.PooledConnectionIdleTimeout, Is.EqualTo(TimeSpan.FromSeconds(55)), "default IdleTimeout = 55s"); Assert.That(handler.ConnectTimeout, Is.EqualTo(TimeSpan.FromSeconds(10)), @@ -63,7 +63,7 @@ public void BaseClient_PositionalConstructor_StillWorks_WithSpecDefaults() var client = new BaseClient(DummyApiKey, DummySecret); var (httpClient, handler) = UnwrapHandler(client); Assert.That(httpClient.Timeout, Is.EqualTo(TimeSpan.FromSeconds(30))); - Assert.That(handler.MaxConnectionsPerServer, Is.EqualTo(5)); + Assert.That(handler.MaxConnectionsPerServer, Is.EqualTo(100)); Assert.That(handler.PooledConnectionIdleTimeout, Is.EqualTo(TimeSpan.FromSeconds(55))); Assert.That(handler.ConnectTimeout, Is.EqualTo(TimeSpan.FromSeconds(10))); Assert.That(handler.AutomaticDecompression.HasFlag(DecompressionMethods.GZip), Is.True); @@ -197,7 +197,7 @@ public void BaseClient_InfoLog_OnConstruction_WithDefaults() Assert.That(capture.Infos.Count, Is.EqualTo(1), "exactly one INFO line on construction"); var msg = capture.Infos[0]; Assert.That(msg, Does.StartWith("client.initialized")); - Assert.That(msg, Does.Contain("stream.client.max_conns_per_host=5")); + Assert.That(msg, Does.Contain("stream.client.max_conns_per_host=100")); Assert.That(msg, Does.Contain("stream.client.idle_timeout_seconds=55")); Assert.That(msg, Does.Contain("stream.client.connect_timeout_seconds=10")); Assert.That(msg, Does.Contain("stream.client.request_timeout_seconds=30"));