Skip to content

Commit 8b57ddd

Browse files
authored
Merge pull request #59 from route4me/yurii-bart-feat-add-httpclients-timeout-01
Yurii bart feat add httpclients timeout 01
2 parents e90dd69 + fc21dc7 commit 8b57ddd

File tree

5 files changed

+182
-1
lines changed

5 files changed

+182
-1
lines changed

route4me-csharp-sdk/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
# Changelog
22
All notable changes to this project will be documented in this file.
33

4+
## [7.13.3] - 2025-12-17
5+
### Changed
6+
- Reduced default HTTP request timeout from 30 minutes to 30 seconds
7+
- Added configurable HTTP timeout via `Route4MeConfig.HttpTimeout` property
8+
- Users can now customize timeout globally before making API calls
9+
410
## [7.13.2] - 2025-01-17
511
### Changed
612
Migrated project to .NET 10.0:

route4me-csharp-sdk/Route4MeSDKLibrary/HttpClientHolderManager.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ internal class HttpClientHolderManager
1818

1919
private static readonly object SyncRoot = new object();
2020

21+
/// <summary>
22+
/// Gets or sets the HTTP request timeout. Default is 30 seconds.
23+
/// Change this value to configure the timeout for all HTTP requests made by the SDK.
24+
/// </summary>
25+
public static TimeSpan RequestsTimeout { get; set; } = TimeSpan.FromSeconds(30);
26+
2127
static HttpClientHolderManager()
2228
{
2329
// ReSharper disable once ObjectCreationAsStatement
@@ -59,7 +65,7 @@ public static void ReleaseHttpClientHolder(string baseAddress)
5965

6066
private static HttpClient CreateHttpClient(string baseAddress, string apiKey = null)
6167
{
62-
var result = new HttpClient { BaseAddress = new Uri(baseAddress), Timeout = TimeSpan.FromMinutes(30) };
68+
var result = new HttpClient { BaseAddress = new Uri(baseAddress), Timeout = RequestsTimeout };
6369

6470
result.DefaultRequestHeaders.Accept.Clear();
6571
result.DefaultRequestHeaders.ConnectionClose = false;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System;
2+
3+
namespace Route4MeSDKLibrary
4+
{
5+
/// <summary>
6+
/// Global configuration settings for the Route4Me SDK.
7+
/// </summary>
8+
public static class Route4MeConfig
9+
{
10+
/// <summary>
11+
/// Gets or sets the HTTP request timeout for all API calls made by the SDK.
12+
/// Default is 30 seconds. Set this value before making any API calls to configure the timeout globally.
13+
/// </summary>
14+
/// <example>
15+
/// // Set a 60-second timeout for all API calls
16+
/// Route4MeConfig.HttpTimeout = TimeSpan.FromSeconds(60);
17+
///
18+
/// // Or use minutes
19+
/// Route4MeConfig.HttpTimeout = TimeSpan.FromMinutes(2);
20+
/// </example>
21+
public static TimeSpan HttpTimeout
22+
{
23+
get => HttpClientHolderManager.RequestsTimeout;
24+
set => HttpClientHolderManager.RequestsTimeout = value;
25+
}
26+
}
27+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
3+
using Route4MeSDKLibrary;
4+
5+
namespace Route4MeSDK.Examples
6+
{
7+
/// <summary>
8+
/// Example demonstrating how to configure the Route4Me SDK globally.
9+
/// </summary>
10+
public sealed partial class Route4MeExamples
11+
{
12+
public void TimeoutConfigurationExample()
13+
{
14+
Console.WriteLine("=== Route4Me SDK Configuration Examples ===\n");
15+
16+
// Example 1: Check default timeout
17+
Console.WriteLine($"Default HTTP timeout: {Route4MeConfig.HttpTimeout.TotalSeconds} seconds");
18+
19+
// Example 2: Set a custom timeout (60 seconds)
20+
Console.WriteLine("\nSetting custom timeout to 60 seconds...");
21+
Route4MeConfig.HttpTimeout = TimeSpan.FromSeconds(60);
22+
Console.WriteLine($"New HTTP timeout: {Route4MeConfig.HttpTimeout.TotalSeconds} seconds");
23+
24+
// Example 3: Set timeout using minutes
25+
Console.WriteLine("\nSetting timeout to 2 minutes...");
26+
Route4MeConfig.HttpTimeout = TimeSpan.FromMinutes(2);
27+
Console.WriteLine($"New HTTP timeout: {Route4MeConfig.HttpTimeout.TotalMinutes} minutes");
28+
29+
// Example 4: Reset to default (30 seconds)
30+
Console.WriteLine("\nResetting to default timeout (30 seconds)...");
31+
Route4MeConfig.HttpTimeout = TimeSpan.FromSeconds(30);
32+
Console.WriteLine($"HTTP timeout: {Route4MeConfig.HttpTimeout.TotalSeconds} seconds");
33+
34+
Console.WriteLine("\n=== Important Notes ===");
35+
Console.WriteLine("- Set the timeout BEFORE making any API calls");
36+
Console.WriteLine("- The timeout applies to all subsequent HTTP requests");
37+
Console.WriteLine("- Default timeout is 30 seconds");
38+
Console.WriteLine("- Increase for long-running operations (e.g., large optimizations)");
39+
Console.WriteLine("- Decrease for faster failure detection in time-sensitive scenarios");
40+
}
41+
}
42+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
using System;
2+
using System.Reflection;
3+
4+
using NUnit.Framework;
5+
6+
using Route4MeSDKLibrary;
7+
8+
namespace Route4MeSdkV5UnitTest.V5
9+
{
10+
[TestFixture]
11+
public class ConfigurationTests
12+
{
13+
[Test]
14+
public void HttpClient_UsesConfiguredTimeout_WhenCreated()
15+
{
16+
// Arrange
17+
var originalTimeout = Route4MeConfig.HttpTimeout;
18+
var customTimeout = TimeSpan.FromSeconds(45);
19+
20+
try
21+
{
22+
// Set custom timeout before creating HttpClient
23+
Route4MeConfig.HttpTimeout = customTimeout;
24+
25+
// Use a unique base address to ensure we get a fresh HttpClient instance
26+
var uniqueBaseAddress = $"https://test-{Guid.NewGuid()}.route4me.com";
27+
28+
// Act - Use reflection to access the internal HttpClientHolderManager
29+
var holderManagerType = Type.GetType("Route4MeSDKLibrary.HttpClientHolderManager, Route4MeSDKLibrary");
30+
Assert.IsNotNull(holderManagerType, "HttpClientHolderManager type not found");
31+
32+
var acquireMethod = holderManagerType.GetMethod("AcquireHttpClientHolder",
33+
BindingFlags.Public | BindingFlags.Static);
34+
Assert.IsNotNull(acquireMethod, "AcquireHttpClientHolder method not found");
35+
36+
var holder = acquireMethod.Invoke(null, new object[] { uniqueBaseAddress, null });
37+
Assert.IsNotNull(holder, "HttpClientHolder should not be null");
38+
39+
// Get the HttpClient from the holder
40+
var httpClientProperty = holder.GetType().GetProperty("HttpClient");
41+
Assert.IsNotNull(httpClientProperty, "HttpClient property not found");
42+
43+
var httpClient = httpClientProperty.GetValue(holder) as System.Net.Http.HttpClient;
44+
Assert.IsNotNull(httpClient, "HttpClient should not be null");
45+
46+
// Assert - Verify the HttpClient has the custom timeout
47+
Assert.AreEqual(customTimeout, httpClient.Timeout,
48+
$"HttpClient timeout should be {customTimeout.TotalSeconds} seconds");
49+
50+
// Cleanup - Release the holder
51+
var releaseMethod = holderManagerType.GetMethod("ReleaseHttpClientHolder",
52+
BindingFlags.Public | BindingFlags.Static);
53+
releaseMethod?.Invoke(null, new object[] { uniqueBaseAddress });
54+
}
55+
finally
56+
{
57+
// Restore original timeout
58+
Route4MeConfig.HttpTimeout = originalTimeout;
59+
}
60+
}
61+
62+
[Test]
63+
public void HttpClient_DefaultTimeout_Is30Seconds_WhenNoConfigurationSet()
64+
{
65+
// Arrange
66+
var originalTimeout = Route4MeConfig.HttpTimeout;
67+
68+
try
69+
{
70+
// Reset to default
71+
Route4MeConfig.HttpTimeout = TimeSpan.FromSeconds(30);
72+
73+
// Use a unique base address to ensure we get a fresh HttpClient instance
74+
var uniqueBaseAddress = $"https://test-default-{Guid.NewGuid()}.route4me.com";
75+
76+
// Act - Use reflection to access the internal HttpClientHolderManager
77+
var holderManagerType = Type.GetType("Route4MeSDKLibrary.HttpClientHolderManager, Route4MeSDKLibrary");
78+
var acquireMethod = holderManagerType.GetMethod("AcquireHttpClientHolder",
79+
BindingFlags.Public | BindingFlags.Static);
80+
var holder = acquireMethod.Invoke(null, new object[] { uniqueBaseAddress, null });
81+
var httpClientProperty = holder.GetType().GetProperty("HttpClient");
82+
var httpClient = httpClientProperty.GetValue(holder) as System.Net.Http.HttpClient;
83+
84+
// Assert - Verify the HttpClient has the default 30-second timeout
85+
Assert.AreEqual(TimeSpan.FromSeconds(30), httpClient.Timeout,
86+
"HttpClient should have default 30-second timeout");
87+
88+
// Cleanup
89+
var releaseMethod = holderManagerType.GetMethod("ReleaseHttpClientHolder",
90+
BindingFlags.Public | BindingFlags.Static);
91+
releaseMethod?.Invoke(null, new object[] { uniqueBaseAddress });
92+
}
93+
finally
94+
{
95+
// Restore original timeout
96+
Route4MeConfig.HttpTimeout = originalTimeout;
97+
}
98+
}
99+
}
100+
}

0 commit comments

Comments
 (0)