From 6ce84423a766857fd966bebf57ea8d49f83b7701 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 6 Aug 2026 08:14:00 +0000 Subject: [PATCH] feat: default requests to a 30 second timeout The 100 second timeout was an openapi-generator leftover rather than a deliberate choice, and it was far longer than the API's own request timeout. Lower the default to 30 seconds behind a named `SeamRequestConfiguration.DefaultTimeout` constant, and add a `timeout` parameter to `SeamClient` so callers can raise or lower it per client. The per-client value takes precedence over the configuration, which remains available for setting the default globally. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01XMgDauUA2R9u2THCHmMgv1 --- README.md | 17 ++++++ .../src/Seam.Test/Client/TimeoutTests.cs | 56 +++++++++++++++++++ output/csharp/src/Seam/Client/Seam.cs | 25 +++++---- .../Seam/Client/SeamRequestConfiguration.cs | 11 +++- output/csharp/src/Seam/README.md | 17 ++++++ 5 files changed, 114 insertions(+), 12 deletions(-) create mode 100644 output/csharp/src/Seam.Test/Client/TimeoutTests.cs diff --git a/README.md b/README.md index 3a76843..4ffaf6a 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,23 @@ Console.WriteLine("First Device Name: " + myDevices[0].Properties.Name); var accessCode = seam.AccessCodes.Create(deviceId: myDevices[0].DeviceId, code: "1234"); ``` +## Advanced Usage + +### Setting the request timeout + +Requests time out after 30 seconds by default. +Pass the `timeout` option, in milliseconds, to override this: + +```csharp +var seam = new SeamClient(apiToken: "YOUR_API_KEY", timeout: 60000); +``` + +The default may also be changed for every client at once: + +```csharp +GlobalSeamRequestConfiguration.Instance.Timeout = 60000; +``` + ## Development and Testing ### Quickstart diff --git a/output/csharp/src/Seam.Test/Client/TimeoutTests.cs b/output/csharp/src/Seam.Test/Client/TimeoutTests.cs new file mode 100644 index 0000000..cecc86d --- /dev/null +++ b/output/csharp/src/Seam.Test/Client/TimeoutTests.cs @@ -0,0 +1,56 @@ +namespace Seam.Test; + +using Seam.Client; + +public class TimeoutTests +{ + [Fact] + public void DefaultTimeoutIs30Seconds() + { + Assert.Equal(30000, SeamRequestConfiguration.DefaultTimeout); + } + + [Fact] + public void NewConfigurationUsesTheDefaultTimeout() + { + var configuration = new SeamRequestConfiguration(); + + Assert.Equal(SeamRequestConfiguration.DefaultTimeout, configuration.Timeout); + } + + [Fact] + public void GlobalConfigurationUsesTheDefaultTimeout() + { + Assert.Equal( + SeamRequestConfiguration.DefaultTimeout, + GlobalSeamRequestConfiguration.Instance.Timeout + ); + } + + [Fact] + public void ConfigurationTimeoutCanBeOverridden() + { + var configuration = new SeamRequestConfiguration { Timeout = 60000 }; + + Assert.Equal(60000, configuration.Timeout); + } + + [Fact] + public void MergedConfigurationTakesTheTimeoutFromTheSecondConfiguration() + { + var first = new SeamRequestConfiguration { Timeout = 60000 }; + var second = new SeamRequestConfiguration { Timeout = 5000 }; + + var merged = SeamRequestConfiguration.MergeConfigurations(first, second); + + Assert.Equal(5000, merged.Timeout); + } + + [Fact] + public void ClientAcceptsATimeout() + { + var seam = new SeamClient(apiToken: "seam_apikey_token", timeout: 60000); + + Assert.NotNull(seam); + } +} diff --git a/output/csharp/src/Seam/Client/Seam.cs b/output/csharp/src/Seam/Client/Seam.cs index a51ebf4..0bad0ff 100644 --- a/output/csharp/src/Seam/Client/Seam.cs +++ b/output/csharp/src/Seam/Client/Seam.cs @@ -178,6 +178,7 @@ public partial class SeamClient : ISeamClient { private readonly string _baseUrl; private readonly string _apiToken; + private readonly int? _timeout; /// /// Specifies the settings on a object. @@ -210,19 +211,22 @@ public partial class SeamClient : ISeamClient /// /// Initializes a new instance of the /// - /// The target service's base path in URL format. /// The target service's API Token. + /// The request timeout in milliseconds. Defaults to + /// . /// - public SeamClient(string apiToken) - : this(GlobalSeamRequestConfiguration.Instance.BasePath, apiToken) { } + public SeamClient(string apiToken, int? timeout = null) + : this(GlobalSeamRequestConfiguration.Instance.BasePath, apiToken, timeout) { } /// /// Initializes a new instance of the /// /// The target service's base path in URL format. /// The target service's API Token. + /// The request timeout in milliseconds. Defaults to + /// . /// - public SeamClient(string basePath, string apiToken) + public SeamClient(string basePath, string apiToken, int? timeout = null) { if (string.IsNullOrEmpty(basePath)) throw new ArgumentException("basePath cannot be empty"); @@ -232,6 +236,7 @@ public SeamClient(string basePath, string apiToken) _baseUrl = basePath; _apiToken = apiToken; + _timeout = timeout; } /// @@ -503,7 +508,7 @@ IReadableSeamRequestConfiguration configuration { ClientCertificates = configuration.ClientCertificates, CookieContainer = cookies, - MaxTimeout = configuration.Timeout, + MaxTimeout = _timeout ?? configuration.Timeout, Proxy = configuration.Proxy, UserAgent = configuration.UserAgent, // UseDefaultCredentials = configuration.UseDefaultCredentials, @@ -633,7 +638,7 @@ private async Task> ExecAsync( var clientOptions = new RestClientOptions(baseUrl) { ClientCertificates = configuration.ClientCertificates, - MaxTimeout = configuration.Timeout, + MaxTimeout = _timeout ?? configuration.Timeout, Proxy = configuration.Proxy, UserAgent = configuration.UserAgent, ThrowOnAnyError = false, @@ -1061,10 +1066,10 @@ public void Dispose() { } [Obsolete("Please use Seam.Client.SeamClient instead")] public class Seam : SeamClient { - public Seam(string apiToken) - : base(apiToken) { } + public Seam(string apiToken, int? timeout = null) + : base(apiToken, timeout) { } - public Seam(string basePath, string apiToken) - : base(basePath, apiToken) { } + public Seam(string basePath, string apiToken, int? timeout = null) + : base(basePath, apiToken, timeout) { } } } diff --git a/output/csharp/src/Seam/Client/SeamRequestConfiguration.cs b/output/csharp/src/Seam/Client/SeamRequestConfiguration.cs index 9ca6418..7c972b7 100644 --- a/output/csharp/src/Seam/Client/SeamRequestConfiguration.cs +++ b/output/csharp/src/Seam/Client/SeamRequestConfiguration.cs @@ -25,6 +25,12 @@ public class SeamRequestConfiguration : IReadableSeamRequestConfiguration /// Version of the package. public const string Version = "1.0.0"; + /// + /// Default HTTP timeout (milliseconds) applied to every request. + /// + /// Default HTTP timeout (milliseconds). + public const int DefaultTimeout = 30000; + /// /// Identifier for ISO 8601 DateTime Format /// @@ -138,7 +144,7 @@ public SeamRequestConfiguration() { }; // Setting Timeout has side effects (forces ApiClient creation). - Timeout = 100000; + Timeout = DefaultTimeout; } /// @@ -221,7 +227,8 @@ public virtual IDictionary DefaultHeader public virtual IDictionary DefaultHeaders { get; set; } /// - /// Gets or sets the HTTP timeout (milliseconds) of ApiClient. Default to 100000 milliseconds. + /// Gets or sets the HTTP timeout (milliseconds) of ApiClient. Defaults to + /// milliseconds. /// public virtual int Timeout { get; set; } diff --git a/output/csharp/src/Seam/README.md b/output/csharp/src/Seam/README.md index 1f42337..8c59e38 100644 --- a/output/csharp/src/Seam/README.md +++ b/output/csharp/src/Seam/README.md @@ -13,3 +13,20 @@ Console.WriteLine("First Device Name: " + myDevices[0].Properties.Name); var accessCode = seam.AccessCodes.Create(deviceId: myDevices[0].DeviceId, code: "1234"); ``` + +## Advanced Usage + +### Setting the request timeout + +Requests time out after 30 seconds by default. +Pass the `timeout` option, in milliseconds, to override this: + +```csharp +var seam = new SeamClient(apiToken: "YOUR_API_KEY", timeout: 60000); +``` + +The default may also be changed for every client at once: + +```csharp +GlobalSeamRequestConfiguration.Instance.Timeout = 60000; +```