From 56431383089eb167ed7e435bebb973d9242544c8 Mon Sep 17 00:00:00 2001 From: NguyenHoangSon96 Date: Thu, 11 Sep 2025 13:24:09 +0700 Subject: [PATCH 01/12] feat: add QueryTimeout and WriteTimeout --- Client.Test.Integration/QueryWriteTest.cs | 46 ++++++++++++++++++++ Client.Test/InfluxDBClientQueryTest.cs | 10 ++--- Client.Test/InfluxDBClientWriteTest.cs | 46 +++++++++----------- Client.Test/Internal/RestClientTest.cs | 13 ------ Client/Config/ClientConfig.cs | 15 ++++++- Client/InfluxDBClient.cs | 53 +++++++++++++++++------ Client/Internal/FlightSqlClient.cs | 19 ++++++-- 7 files changed, 140 insertions(+), 62 deletions(-) diff --git a/Client.Test.Integration/QueryWriteTest.cs b/Client.Test.Integration/QueryWriteTest.cs index 1c9acc6..a85b490 100644 --- a/Client.Test.Integration/QueryWriteTest.cs +++ b/Client.Test.Integration/QueryWriteTest.cs @@ -190,4 +190,50 @@ public void GrpcDeadline() }); Assert.That(ex.StatusCode, Is.EqualTo(StatusCode.DeadlineExceeded)); } + + [Test] + public Task TimeoutExceededByDeadline() + { + using var client = new InfluxDBClient(new ClientConfig + { + Host = Host, + Token = Token, + Database = Database, + QueryTimeout = TimeSpan.FromSeconds(100), + QueryOptions = new QueryOptions() + { + Deadline = DateTime.UtcNow.AddMilliseconds(1) // Deadline will have a higher priority than QueryTimeout + } + }); + var ex = Assert.ThrowsAsync(async () => + { + await foreach (var v in client.Query("SELECT * FROM weathers LIMIT 5")) + { + } + }); + Assert.That(ex, Is.Not.Null);; + Assert.That(ex.StatusCode, Is.EqualTo(StatusCode.DeadlineExceeded)); + return Task.CompletedTask; + } + + [Test] + public Task TimeoutExceededByQueryTimeout() + { + using var client = new InfluxDBClient(new ClientConfig + { + Host = Host, + Token = Token, + Database = Database, + QueryTimeout = TimeSpan.FromMilliseconds(1), + }); + var ex = Assert.ThrowsAsync(async () => + { + await foreach (var v in client.Query("SELECT * FROM weathers LIMIT 5")) + { + } + }); + Assert.That(ex, Is.Not.Null);; + Assert.That(ex.StatusCode, Is.EqualTo(StatusCode.DeadlineExceeded)); + return Task.CompletedTask; + } } \ No newline at end of file diff --git a/Client.Test/InfluxDBClientQueryTest.cs b/Client.Test/InfluxDBClientQueryTest.cs index e34008d..18250ea 100644 --- a/Client.Test/InfluxDBClientQueryTest.cs +++ b/Client.Test/InfluxDBClientQueryTest.cs @@ -54,7 +54,7 @@ public async Task PassNamedParametersToFlightClient() var mockFlightSqlClient = new Mock(); mockFlightSqlClient .Setup(m => m.Execute(It.IsAny(), It.IsAny(), It.IsAny(), - It.IsAny>(), It.IsAny>())) + It.IsAny>(), It.IsAny>(), It.IsAny())) .Returns(new List().ToAsyncEnumerable()); // @@ -74,9 +74,9 @@ public async Task PassNamedParametersToFlightClient() { "max-frequency", 3.5 } }; - _ = await _client.QueryPoints(query, database: "my-db", queryType: queryType, namedParameters: namedParameters) + _ = await _client.QueryPoints(query, database: "my-db", queryType: queryType, namedParameters: namedParameters, timeout: TimeSpan.MaxValue) .ToListAsync(); - mockFlightSqlClient.Verify(m => m.Execute(query, "my-db", queryType, namedParameters, new Dictionary()), Times.Exactly(1)); + mockFlightSqlClient.Verify(m => m.Execute(query, "my-db", queryType, namedParameters, new Dictionary(), TimeSpan.MaxValue), Times.Exactly(1)); } [Test] @@ -109,7 +109,7 @@ public async Task PassHeadersToFlightClient() var mockFlightSqlClient = new Mock(); mockFlightSqlClient .Setup(m => m.Execute(It.IsAny(), It.IsAny(), It.IsAny(), - It.IsAny>(), It.IsAny>())) + It.IsAny>(), It.IsAny>(), It.IsAny())) .Returns(new List().ToAsyncEnumerable()); // @@ -128,6 +128,6 @@ public async Task PassHeadersToFlightClient() }}; _ = await _client.QueryPoints(query, database: "my-db", queryType: queryType, headers: headers) .ToListAsync(); - mockFlightSqlClient.Verify(m => m.Execute(query, "my-db", queryType, new Dictionary(), headers), Times.Exactly(1)); + mockFlightSqlClient.Verify(m => m.Execute(query, "my-db", queryType, new Dictionary(), headers, null), Times.Exactly(1)); } } \ No newline at end of file diff --git a/Client.Test/InfluxDBClientWriteTest.cs b/Client.Test/InfluxDBClientWriteTest.cs index c97c09a..9da6126 100644 --- a/Client.Test/InfluxDBClientWriteTest.cs +++ b/Client.Test/InfluxDBClientWriteTest.cs @@ -2,13 +2,13 @@ using System.Collections.Generic; using System.Linq; using System.Net; -using System.Net.Http; using System.Threading.Tasks; using InfluxDB3.Client.Config; using InfluxDB3.Client.Write; using WireMock.Matchers; using WireMock.RequestBuilders; using WireMock.ResponseBuilders; +using WriteOptions = InfluxDB3.Client.Config.WriteOptions; namespace InfluxDB3.Client.Test; @@ -493,55 +493,49 @@ public void WriteNoSyncTrueNotSupported() } [Test] - public async Task TestSetHttpClient() + public void TimeoutExceeded() { MockServer .Given(Request.Create().WithPath("/api/v2/write").UsingPost()) - .RespondWith(Response.Create().WithStatusCode(HttpStatusCode.OK)); - - var httpClient = new HttpClient(); - httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("my-user-agent"); - httpClient.DefaultRequestHeaders.Add("X-Client-ID", "123"); + .RespondWith(Response.Create().WithStatusCode(204).WithDelay(TimeSpan.FromSeconds(2))); _client = new InfluxDBClient(new ClientConfig { Host = MockServerUrl, Token = "my-token", Database = "my-database", - HttpClient = httpClient + Timeout = TimeSpan.FromSeconds(1) }); - await _client.WriteRecordAsync("mem,tag=a field=1"); - var requests = MockServer.LogEntries.ToList(); - using (Assert.EnterMultipleScope()) + //fixme should be TaskCanceledException or TimeoutException + var ae = Assert.ThrowsAsync(async () => { - Assert.That(requests[0].RequestMessage.Headers?["User-Agent"].First(), Is.EqualTo("my-user-agent")); - Assert.That(requests[0].RequestMessage.Headers["X-Client-ID"].First(), Is.EqualTo("123")); - } - Assert.Pass(); + await _client.WriteRecordAsync("mem,tag=a field=1"); + }); + + Assert.That(ae, Is.Not.Null); } [Test] - public void TestCheckHttpClientStillOpen() + public void TimeoutExceededByWriteTimeout() { MockServer - .Given(Request.Create().WithPath("/test").UsingGet()) - .RespondWith( - Response.Create() - .WithStatusCode(HttpStatusCode.OK) - .WithBody("Still ok")); + .Given(Request.Create().WithPath("/api/v2/write").UsingPost()) + .RespondWith(Response.Create().WithStatusCode(204).WithDelay(TimeSpan.FromSeconds(2))); - var httpClient = new HttpClient(new HttpClientHandler()); _client = new InfluxDBClient(new ClientConfig { Host = MockServerUrl, Token = "my-token", Database = "my-database", - HttpClient = httpClient + Timeout = TimeSpan.FromSeconds(11), + WriteTimeout = TimeSpan.FromSeconds(1) // WriteTimeout has a higher priority than Timeout + }); + var ae = Assert.ThrowsAsync(async () => + { + await _client.WriteRecordAsync("mem,tag=a field=1"); }); - _client.Dispose(); - var httpResponseMessage = httpClient.Send(new HttpRequestMessage(HttpMethod.Get, "test")); - Assert.That(httpResponseMessage.Content.ReadAsStringAsync().Result, Is.EqualTo("Still ok")); + Assert.That(ae, Is.Not.Null); } } \ No newline at end of file diff --git a/Client.Test/Internal/RestClientTest.cs b/Client.Test/Internal/RestClientTest.cs index 07a02bb..d4a0b5f 100644 --- a/Client.Test/Internal/RestClientTest.cs +++ b/Client.Test/Internal/RestClientTest.cs @@ -279,19 +279,6 @@ public void AllowHttpRedirects() Assert.That(_client, Is.Not.Null); } - [Test] - public void Timeout() - { - CreateAndConfigureRestClient(new ClientConfig - { - Host = MockServerUrl, - Timeout = TimeSpan.FromSeconds(45) - }); - - var httpClient = GetDeclaredField(_client.GetType(), _client, "_httpClient"); - Assert.That(httpClient.Timeout, Is.EqualTo(TimeSpan.FromSeconds(45))); - } - private void CreateAndConfigureRestClient(ClientConfig config) { _httpClient = InfluxDBClient.CreateOrGetHttpClient(config); diff --git a/Client/Config/ClientConfig.cs b/Client/Config/ClientConfig.cs index 7d318af..c687bf6 100644 --- a/Client/Config/ClientConfig.cs +++ b/Client/Config/ClientConfig.cs @@ -19,7 +19,9 @@ namespace InfluxDB3.Client.Config; /// - Organization: The organization to be used for operations. /// - Database: The database to be used for InfluxDB operations. /// - Headers: The set of HTTP headers to be included in requests. -/// - Timeout: Timeout to wait before the HTTP request times out. Default to '10 seconds'. +/// - [Deprecated] Timeout: Timeout to wait before the HTTP request times out. Default to '10 seconds'. +/// - QueryTimeout: The maximum duration to wait for a query to complete before timing out. +/// - WriteTimeout: The duration to wait before timing out a write operation to the InfluxDB server. /// - AllowHttpRedirects: Automatically following HTTP 3xx redirects. Default to 'false'. /// - DisableServerCertificateValidation: Disable server SSL certificate validation. Default to 'false'. /// - DisableCertificateRevocationListCheck: Disable SSL certificate revocation list (CRL) checking. Default to 'false'. @@ -165,8 +167,19 @@ public string Host /// /// Timeout to wait before the HTTP request times out. Default to '10 seconds'. /// + [Obsolete("Please use more informative properties like WriteTimeout or QueryTimeout")] public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(10); + /// + /// The maximum duration to wait for a query to complete before timing out. + /// + public TimeSpan? QueryTimeout { get; set; } + + /// + /// The duration to wait before timing out a write operation to the InfluxDB server. + /// + public TimeSpan? WriteTimeout { get; set; } + /// /// Automatically following HTTP 3xx redirects. Default to 'false'. /// diff --git a/Client/InfluxDBClient.cs b/Client/InfluxDBClient.cs index 90b1e1e..dd81d24 100644 --- a/Client/InfluxDBClient.cs +++ b/Client/InfluxDBClient.cs @@ -62,10 +62,13 @@ public interface IInfluxDBClient : IDisposable /// The headers to be added to query request. The headers specified here are preferred over /// the headers specified in the client configuration. /// + /// + /// The timeout to use for only this query request. + /// /// Batches of rows /// The client is already disposed IAsyncEnumerable Query(string query, QueryType? queryType = null, string? database = null, - Dictionary? namedParameters = null, Dictionary? headers = null); + Dictionary? namedParameters = null, Dictionary? headers = null, TimeSpan? timeout = null); /// /// Query data from InfluxDB IOx using FlightSQL. @@ -108,10 +111,13 @@ public interface IInfluxDBClient : IDisposable /// The headers to be added to query request. The headers specified here are preferred over /// the headers specified in the client configuration. /// + /// + /// The timeout to use for only this query request. + /// /// Batches of rows /// The client is already disposed IAsyncEnumerable QueryBatches(string query, QueryType? queryType = null, string? database = null, - Dictionary? namedParameters = null, Dictionary? headers = null); + Dictionary? namedParameters = null, Dictionary? headers = null, TimeSpan? timeout = null); /// /// Query data from InfluxDB IOx into PointData structure using FlightSQL. @@ -153,11 +159,14 @@ IAsyncEnumerable QueryBatches(string query, QueryType? queryType = /// The headers to be added to query request. The headers specified here are preferred over /// the headers specified in the client configuration. /// + /// + /// The timeout to use for only this query request. + /// /// Batches of rows /// The client is already disposed IAsyncEnumerable QueryPoints(string query, QueryType? queryType = null, string? database = null, Dictionary? namedParameters = null, - Dictionary? headers = null); + Dictionary? headers = null, TimeSpan? timeout = null); /// /// Write data to InfluxDB. @@ -467,13 +476,16 @@ public InfluxDBClient() : this( /// The headers to be added to query request. The headers specified here are preferred over /// the headers specified in the client configuration. /// + /// + /// The timeout to use for only this query request. + /// /// Batches of rows /// The client is already disposed public async IAsyncEnumerable Query(string query, QueryType? queryType = null, string? database = null, Dictionary? namedParameters = null, - Dictionary? headers = null) + Dictionary? headers = null, TimeSpan? timeout = null) { - await foreach (var batch in QueryBatches(query, queryType, database, namedParameters, headers) + await foreach (var batch in QueryBatches(query, queryType, database, namedParameters, headers, timeout) .ConfigureAwait(false)) { for (var i = 0; i < batch.Column(0).Length; i++) @@ -537,13 +549,16 @@ public InfluxDBClient() : this( /// The headers to be added to query request. The headers specified here are preferred over /// the headers specified in the client configuration. /// + /// + /// The timeout to use for only this query request. + /// /// Batches of rows /// The client is already disposed public async IAsyncEnumerable QueryPoints(string query, QueryType? queryType = null, string? database = null, Dictionary? namedParameters = null, - Dictionary? headers = null) + Dictionary? headers = null, TimeSpan? timeout = null) { - await foreach (var batch in QueryBatches(query, queryType, database, namedParameters, headers) + await foreach (var batch in QueryBatches(query, queryType, database, namedParameters, headers, timeout) .ConfigureAwait(false)) { for (var i = 0; i < batch.Column(0).Length; i++) @@ -595,11 +610,14 @@ public async IAsyncEnumerable QueryPoints(string query, QueryTy /// The headers to be added to query request. The headers specified here are preferred over /// the headers specified in the client configuration. /// + /// + /// The timeout to use for only this query request. + /// /// Batches of rows /// The client is already disposed public IAsyncEnumerable QueryBatches(string query, QueryType? queryType = null, string? database = null, Dictionary? namedParameters = null, - Dictionary? headers = null) + Dictionary? headers = null, TimeSpan? timeout = null) { if (_disposed) { @@ -610,7 +628,7 @@ public IAsyncEnumerable QueryBatches(string query, QueryType? query (database ?? _config.Database) ?? throw new InvalidOperationException(OptionMessage("database")), queryType ?? QueryType.SQL, namedParameters ?? new Dictionary(), - headers ?? new Dictionary()); + headers ?? new Dictionary(), timeout); } /// @@ -786,10 +804,20 @@ var databaseNotNull }; } + var cancelToken = cancellationToken; + if (!cancelToken.IsCancellationRequested && _config.WriteTimeout.HasValue) + { + cancelToken = new CancellationTokenSource(_config.WriteTimeout.Value).Token; + } + else + { + cancelToken = new CancellationTokenSource(_config.Timeout).Token; + } + try { await _restClient - .Request(path, HttpMethod.Post, content, queryParams, headers, cancellationToken) + .Request(path, HttpMethod.Post, content, queryParams, headers, cancelToken) .ConfigureAwait(false); } catch (InfluxDBApiException e) @@ -938,10 +966,7 @@ private static HttpClient CreateHttpClient(ClientConfig config) handler.CheckCertificateRevocationList = false; } - var client = new HttpClient(handler) - { - Timeout = config.Timeout - }; + var client = new HttpClient(handler); client.DefaultRequestHeaders.UserAgent.ParseAdd(AssemblyHelper.GetUserAgent()); return client; diff --git a/Client/Internal/FlightSqlClient.cs b/Client/Internal/FlightSqlClient.cs index 52ae53e..2aa5bde 100644 --- a/Client/Internal/FlightSqlClient.cs +++ b/Client/Internal/FlightSqlClient.cs @@ -25,7 +25,7 @@ internal interface IFlightSqlClient : IDisposable /// Execute the query and return the result as a sequence of record batches. /// internal IAsyncEnumerable Execute(string query, string database, QueryType queryType, - Dictionary namedParameters, Dictionary headers); + Dictionary namedParameters, Dictionary headers, TimeSpan? timeout = null); /// /// Prepare the FlightTicket for the query. @@ -77,7 +77,7 @@ internal FlightSqlClient(ClientConfig config, HttpClient httpClient) } async IAsyncEnumerable IFlightSqlClient.Execute(string query, string database, QueryType queryType, - Dictionary namedParameters, Dictionary headers) + Dictionary namedParameters, Dictionary headers, TimeSpan? timeout) { // // verify that values of namedParameters is supported type @@ -97,7 +97,20 @@ async IAsyncEnumerable IFlightSqlClient.Execute(string query, strin var ticket = ((IFlightSqlClient)this).PrepareFlightTicket(query, database, queryType, namedParameters); - using var stream = _flightClient.GetStream(ticket, metadata, _config.QueryOptions.Deadline); + DateTime? deadline = null; + if (timeout.HasValue) + { + deadline = DateTime.UtcNow.Add(timeout.Value); + } else if (_config.QueryOptions.Deadline.HasValue) + { + deadline = _config.QueryOptions.Deadline.Value; + } + else if (_config.QueryTimeout.HasValue) + { + deadline = DateTime.UtcNow.Add(_config.QueryTimeout.Value); + } + + using var stream = _flightClient.GetStream(ticket, metadata, deadline); while (await stream.ResponseStream.MoveNext().ConfigureAwait(false)) { yield return stream.ResponseStream.Current; From e7c5cc0c44e58cd96b8a49e7be969cfdfd2faae8 Mon Sep 17 00:00:00 2001 From: NguyenHoangSon96 Date: Thu, 11 Sep 2025 14:19:46 +0700 Subject: [PATCH 02/12] test: add test cases --- Client.Test.Integration/QueryWriteTest.cs | 30 +++++++++++++++++++++- Client.Test/InfluxDBClientWriteTest.cs | 31 +++++++++++++++++++++-- Client/InfluxDBClient.cs | 29 +++++++++++---------- 3 files changed, 73 insertions(+), 17 deletions(-) diff --git a/Client.Test.Integration/QueryWriteTest.cs b/Client.Test.Integration/QueryWriteTest.cs index a85b490..36a57a7 100644 --- a/Client.Test.Integration/QueryWriteTest.cs +++ b/Client.Test.Integration/QueryWriteTest.cs @@ -199,7 +199,8 @@ public Task TimeoutExceededByDeadline() Host = Host, Token = Token, Database = Database, - QueryTimeout = TimeSpan.FromSeconds(100), + WriteTimeout = TimeSpan.FromSeconds(11), + QueryTimeout = TimeSpan.FromSeconds(11), QueryOptions = new QueryOptions() { Deadline = DateTime.UtcNow.AddMilliseconds(1) // Deadline will have a higher priority than QueryTimeout @@ -224,6 +225,7 @@ public Task TimeoutExceededByQueryTimeout() Host = Host, Token = Token, Database = Database, + WriteTimeout = TimeSpan.FromSeconds(11), QueryTimeout = TimeSpan.FromMilliseconds(1), }); var ex = Assert.ThrowsAsync(async () => @@ -236,4 +238,30 @@ public Task TimeoutExceededByQueryTimeout() Assert.That(ex.StatusCode, Is.EqualTo(StatusCode.DeadlineExceeded)); return Task.CompletedTask; } + + [Test] + public Task TimeoutExceeded() + { + using var client = new InfluxDBClient(new ClientConfig + { + Host = Host, + Token = Token, + Database = Database, + WriteTimeout = TimeSpan.FromSeconds(11), + QueryTimeout = TimeSpan.FromSeconds(11), + QueryOptions = + { + Deadline = DateTime.UtcNow.AddSeconds(11), + } + }); + var ex = Assert.ThrowsAsync(async () => + { + await foreach (var v in client.Query("SELECT * FROM weathers LIMIT 5", timeout: TimeSpan.FromMilliseconds(1))) + { + } + }); + Assert.That(ex, Is.Not.Null);; + Assert.That(ex.StatusCode, Is.EqualTo(StatusCode.DeadlineExceeded)); + return Task.CompletedTask; + } } \ No newline at end of file diff --git a/Client.Test/InfluxDBClientWriteTest.cs b/Client.Test/InfluxDBClientWriteTest.cs index 9da6126..3baf126 100644 --- a/Client.Test/InfluxDBClientWriteTest.cs +++ b/Client.Test/InfluxDBClientWriteTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; +using System.Threading; using System.Threading.Tasks; using InfluxDB3.Client.Config; using InfluxDB3.Client.Write; @@ -493,7 +494,7 @@ public void WriteNoSyncTrueNotSupported() } [Test] - public void TimeoutExceeded() + public void TimeoutExceededByTimeout() { MockServer .Given(Request.Create().WithPath("/api/v2/write").UsingPost()) @@ -517,7 +518,7 @@ public void TimeoutExceeded() } [Test] - public void TimeoutExceededByWriteTimeout() + public Task TimeoutExceededByWriteTimeout() { MockServer .Given(Request.Create().WithPath("/api/v2/write").UsingPost()) @@ -528,6 +529,7 @@ public void TimeoutExceededByWriteTimeout() Host = MockServerUrl, Token = "my-token", Database = "my-database", + QueryTimeout = TimeSpan.FromSeconds(11), Timeout = TimeSpan.FromSeconds(11), WriteTimeout = TimeSpan.FromSeconds(1) // WriteTimeout has a higher priority than Timeout }); @@ -536,6 +538,31 @@ public void TimeoutExceededByWriteTimeout() await _client.WriteRecordAsync("mem,tag=a field=1"); }); + Assert.That(ae, Is.Not.Null); + return Task.CompletedTask; + } + + [Test] + public void TimeoutExceededByToken() + { + MockServer + .Given(Request.Create().WithPath("/api/v2/write").UsingPost()) + .RespondWith(Response.Create().WithStatusCode(204).WithDelay(TimeSpan.FromSeconds(2))); + + _client = new InfluxDBClient(new ClientConfig + { + Host = MockServerUrl, + Token = "my-token", + Database = "my-database", + QueryTimeout = TimeSpan.FromSeconds(11), + Timeout = TimeSpan.FromSeconds(11), + WriteTimeout = TimeSpan.FromSeconds(11) + }); + var ae = Assert.ThrowsAsync(async () => + { + await _client.WriteRecordAsync("mem,tag=a field=1", cancellationToken: new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token); + }); + Assert.That(ae, Is.Not.Null); } } \ No newline at end of file diff --git a/Client/InfluxDBClient.cs b/Client/InfluxDBClient.cs index dd81d24..e859674 100644 --- a/Client/InfluxDBClient.cs +++ b/Client/InfluxDBClient.cs @@ -193,7 +193,7 @@ IAsyncEnumerable QueryPoints(string query, QueryType? queryType /// /// specifies the token to monitor for cancellation requests. Task WriteRecordAsync(string record, string? database = null, WritePrecision? precision = null, - Dictionary? headers = null, CancellationToken cancellationToken = default); + Dictionary? headers = null, CancellationToken? cancellationToken = null); /// /// Write data to InfluxDB. @@ -220,7 +220,7 @@ Task WriteRecordAsync(string record, string? database = null, WritePrecision? pr /// /// specifies the token to monitor for cancellation requests. Task WriteRecordsAsync(IEnumerable records, string? database = null, WritePrecision? precision = null, - Dictionary? headers = null, CancellationToken cancellationToken = default); + Dictionary? headers = null, CancellationToken? cancellationToken = null); /// /// Write data to InfluxDB. @@ -246,7 +246,7 @@ Task WriteRecordsAsync(IEnumerable records, string? database = null, Wri /// /// specifies the token to monitor for cancellation requests. Task WritePointAsync(PointData point, string? database = null, WritePrecision? precision = null, - Dictionary? headers = null, CancellationToken cancellationToken = default); + Dictionary? headers = null, CancellationToken? cancellationToken = null); /// /// Write data to InfluxDB. @@ -276,7 +276,7 @@ Task WritePointAsync(PointData point, string? database = null, WritePrecision? p /// /// specifies the token to monitor for cancellation requests. Task WritePointsAsync(IEnumerable points, string? database = null, WritePrecision? precision = null, - Dictionary? headers = null, CancellationToken cancellationToken = default); + Dictionary? headers = null, CancellationToken? cancellationToken = null); /// /// Retrieves the server version of the connected InfluxDB instance. @@ -657,7 +657,7 @@ public IAsyncEnumerable QueryBatches(string query, QueryType? query /// /// specifies the token to monitor for cancellation requests. public Task WriteRecordAsync(string record, string? database = null, WritePrecision? precision = null, - Dictionary? headers = null, CancellationToken cancellationToken = default) + Dictionary? headers = null, CancellationToken? cancellationToken = null) { return WriteRecordsAsync(new[] { record }, database, precision, headers, cancellationToken); } @@ -688,7 +688,7 @@ public Task WriteRecordAsync(string record, string? database = null, WritePrecis /// specifies the token to monitor for cancellation requests. public Task WriteRecordsAsync(IEnumerable records, string? database = null, WritePrecision? precision = null, Dictionary? headers = null, - CancellationToken cancellationToken = default) + CancellationToken? cancellationToken = null) { return WriteData(records, database, precision, headers, cancellationToken); } @@ -717,7 +717,7 @@ public Task WriteRecordsAsync(IEnumerable records, string? database = nu /// /// specifies the token to monitor for cancellation requests. public Task WritePointAsync(PointData point, string? database = null, WritePrecision? precision = null, - Dictionary? headers = null, CancellationToken cancellationToken = default) + Dictionary? headers = null, CancellationToken? cancellationToken = null) { return WritePointsAsync(new[] { point }, database, precision, headers, cancellationToken); } @@ -751,14 +751,15 @@ public Task WritePointAsync(PointData point, string? database = null, WritePreci /// specifies the token to monitor for cancellation requests. public Task WritePointsAsync(IEnumerable points, string? database = null, WritePrecision? precision = null, Dictionary? headers = null, - CancellationToken cancellationToken = default) + CancellationToken? cancellationToken = null) { return WriteData(points, database, precision, headers, cancellationToken); } private async Task WriteData(IEnumerable data, string? database = null, WritePrecision? precision = null, Dictionary? headers = null, - CancellationToken cancellationToken = default) + CancellationToken? cancellationToken = null) + { if (_disposed) { @@ -804,14 +805,14 @@ var databaseNotNull }; } - var cancelToken = cancellationToken; - if (!cancelToken.IsCancellationRequested && _config.WriteTimeout.HasValue) + var cancelToken = new CancellationTokenSource(_config.Timeout).Token; // Just for compatibility with the old API + if (cancellationToken.HasValue) { - cancelToken = new CancellationTokenSource(_config.WriteTimeout.Value).Token; + cancelToken = cancellationToken.Value; } - else + else if (_config.WriteTimeout.HasValue) { - cancelToken = new CancellationTokenSource(_config.Timeout).Token; + cancelToken = new CancellationTokenSource(_config.WriteTimeout.Value).Token; } try From 986b92e21911fffcafd1752fe06f962ffeacd1b9 Mon Sep 17 00:00:00 2001 From: NguyenHoangSon96 Date: Thu, 11 Sep 2025 15:26:57 +0700 Subject: [PATCH 03/12] test: add test cases --- Client.Test.Integration/QueryWriteTest.cs | 62 +++++++++++++------ Client.Test/InfluxDBClientWriteTest.cs | 74 +++++++++++++++++------ 2 files changed, 99 insertions(+), 37 deletions(-) diff --git a/Client.Test.Integration/QueryWriteTest.cs b/Client.Test.Integration/QueryWriteTest.cs index 36a57a7..6bd2a37 100644 --- a/Client.Test.Integration/QueryWriteTest.cs +++ b/Client.Test.Integration/QueryWriteTest.cs @@ -206,14 +206,10 @@ public Task TimeoutExceededByDeadline() Deadline = DateTime.UtcNow.AddMilliseconds(1) // Deadline will have a higher priority than QueryTimeout } }); - var ex = Assert.ThrowsAsync(async () => - { - await foreach (var v in client.Query("SELECT * FROM weathers LIMIT 5")) - { - } - }); - Assert.That(ex, Is.Not.Null);; - Assert.That(ex.StatusCode, Is.EqualTo(StatusCode.DeadlineExceeded)); + TestQuery(client); + TestQueryBatches(client); + TestQueryPoints(client); + return Task.CompletedTask; } @@ -228,15 +224,12 @@ public Task TimeoutExceededByQueryTimeout() WriteTimeout = TimeSpan.FromSeconds(11), QueryTimeout = TimeSpan.FromMilliseconds(1), }); - var ex = Assert.ThrowsAsync(async () => - { - await foreach (var v in client.Query("SELECT * FROM weathers LIMIT 5")) - { - } - }); - Assert.That(ex, Is.Not.Null);; - Assert.That(ex.StatusCode, Is.EqualTo(StatusCode.DeadlineExceeded)); + TestQuery(client); + TestQueryBatches(client); + TestQueryPoints(client); + return Task.CompletedTask; + } [Test] @@ -254,14 +247,45 @@ public Task TimeoutExceeded() Deadline = DateTime.UtcNow.AddSeconds(11), } }); + + var timeout = TimeSpan.FromMilliseconds(1); + TestQuery(client, timeout); + TestQueryBatches(client, timeout); + TestQueryPoints(client, timeout); + + return Task.FromResult(Task.CompletedTask); + } + + private static void TestQuery(InfluxDBClient client, TimeSpan? timeout = null) + { var ex = Assert.ThrowsAsync(async () => { - await foreach (var v in client.Query("SELECT * FROM weathers LIMIT 5", timeout: TimeSpan.FromMilliseconds(1))) + await foreach (var _ in client.Query("SELECT * FROM weathers LIMIT 5", timeout: timeout)) + { + } + }); + Assert.That(ex.StatusCode, Is.EqualTo(StatusCode.DeadlineExceeded)); + } + + private static void TestQueryBatches(InfluxDBClient client, TimeSpan? timeout = null) + { + var ex = Assert.ThrowsAsync(async () => + { + await foreach (var _ in client.QueryBatches("SELECT * FROM weathers LIMIT 5", timeout: timeout)) + { + } + }); + Assert.That(ex.StatusCode, Is.EqualTo(StatusCode.DeadlineExceeded)); + } + + private static void TestQueryPoints(InfluxDBClient client, TimeSpan? timeout = null) + { + var ex = Assert.ThrowsAsync(async () => + { + await foreach (var _ in client.QueryPoints("SELECT * FROM weathers LIMIT 5", timeout: timeout)) { } }); - Assert.That(ex, Is.Not.Null);; Assert.That(ex.StatusCode, Is.EqualTo(StatusCode.DeadlineExceeded)); - return Task.CompletedTask; } } \ No newline at end of file diff --git a/Client.Test/InfluxDBClientWriteTest.cs b/Client.Test/InfluxDBClientWriteTest.cs index 3baf126..1683368 100644 --- a/Client.Test/InfluxDBClientWriteTest.cs +++ b/Client.Test/InfluxDBClientWriteTest.cs @@ -507,18 +507,14 @@ public void TimeoutExceededByTimeout() Database = "my-database", Timeout = TimeSpan.FromSeconds(1) }); - - //fixme should be TaskCanceledException or TimeoutException - var ae = Assert.ThrowsAsync(async () => - { - await _client.WriteRecordAsync("mem,tag=a field=1"); - }); - - Assert.That(ae, Is.Not.Null); + TestWriteRecordAsync(_client); + TestWriteRecordsAsync(_client); + TestWritePointAsync(_client); + TestWritePointsAsync(_client); } [Test] - public Task TimeoutExceededByWriteTimeout() + public void TimeoutExceededByWriteTimeout() { MockServer .Given(Request.Create().WithPath("/api/v2/write").UsingPost()) @@ -533,13 +529,11 @@ public Task TimeoutExceededByWriteTimeout() Timeout = TimeSpan.FromSeconds(11), WriteTimeout = TimeSpan.FromSeconds(1) // WriteTimeout has a higher priority than Timeout }); - var ae = Assert.ThrowsAsync(async () => - { - await _client.WriteRecordAsync("mem,tag=a field=1"); - }); + TestWriteRecordAsync(_client); + TestWriteRecordsAsync(_client); + TestWritePointAsync(_client); + TestWritePointsAsync(_client); - Assert.That(ae, Is.Not.Null); - return Task.CompletedTask; } [Test] @@ -558,11 +552,55 @@ public void TimeoutExceededByToken() Timeout = TimeSpan.FromSeconds(11), WriteTimeout = TimeSpan.FromSeconds(11) }); - var ae = Assert.ThrowsAsync(async () => + var cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token; + TestWriteRecordAsync(_client, cancellationToken); + TestWriteRecordsAsync(_client, cancellationToken); + TestWritePointAsync(_client, cancellationToken); + TestWritePointsAsync(_client, cancellationToken); + } + + private static void TestWriteRecordAsync(InfluxDBClient client, CancellationToken? cancellationToken = null) + { + Assert.ThrowsAsync(async () => { - await _client.WriteRecordAsync("mem,tag=a field=1", cancellationToken: new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token); + await client.WriteRecordAsync("mem,tag=a field=1", cancellationToken: cancellationToken); }); + } - Assert.That(ae, Is.Not.Null); + private static void TestWriteRecordsAsync(InfluxDBClient client, CancellationToken? cancellationToken = null) + { + Assert.ThrowsAsync(async () => + { + await client.WriteRecordsAsync( + records: new[] { "stat,unit=temperature value=24.5", "stat,unit=temperature value=25.5" }, + cancellationToken: cancellationToken + ); + }); + } + + private static void TestWritePointAsync(InfluxDBClient client, CancellationToken? cancellationToken = null) + { + Assert.ThrowsAsync(async () => + { + await client.WritePointAsync( + PointData.Measurement("h2o").SetTag("location", "europe").SetField("level", 2), + cancellationToken: cancellationToken + ); + }); + } + + private static void TestWritePointsAsync(InfluxDBClient client, CancellationToken? cancellationToken = null) + { + Assert.ThrowsAsync(async () => + { + await client.WritePointsAsync( + points: new[] + { + PointData.Measurement("h2o").SetTag("location", "europe").SetField("level", 2), + PointData.Measurement("h2o").SetTag("location", "us-west").SetField("level", 4), + }, + cancellationToken: cancellationToken + ); + }); } } \ No newline at end of file From 2345f9b11df06c6fee8e1895f0be51cdb072d68b Mon Sep 17 00:00:00 2001 From: NguyenHoangSon96 Date: Thu, 11 Sep 2025 15:32:37 +0700 Subject: [PATCH 04/12] chore: dotnet format --- Client/InfluxDBClient.cs | 2 +- Client/Internal/FlightSqlClient.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Client/InfluxDBClient.cs b/Client/InfluxDBClient.cs index e859674..5948bc9 100644 --- a/Client/InfluxDBClient.cs +++ b/Client/InfluxDBClient.cs @@ -759,7 +759,7 @@ public Task WritePointsAsync(IEnumerable points, string? database = n private async Task WriteData(IEnumerable data, string? database = null, WritePrecision? precision = null, Dictionary? headers = null, CancellationToken? cancellationToken = null) - + { if (_disposed) { diff --git a/Client/Internal/FlightSqlClient.cs b/Client/Internal/FlightSqlClient.cs index 2aa5bde..eb7b682 100644 --- a/Client/Internal/FlightSqlClient.cs +++ b/Client/Internal/FlightSqlClient.cs @@ -101,7 +101,8 @@ async IAsyncEnumerable IFlightSqlClient.Execute(string query, strin if (timeout.HasValue) { deadline = DateTime.UtcNow.Add(timeout.Value); - } else if (_config.QueryOptions.Deadline.HasValue) + } + else if (_config.QueryOptions.Deadline.HasValue) { deadline = _config.QueryOptions.Deadline.Value; } From 2371833d7f7cf2ad349229878241ea5ffc08b09a Mon Sep 17 00:00:00 2001 From: NguyenHoangSon96 Date: Thu, 11 Sep 2025 15:42:03 +0700 Subject: [PATCH 05/12] [EMPTY] trigger CI From 4d15fc1841dd9415a71c959fc8e88ce1e6fb7920 Mon Sep 17 00:00:00 2001 From: NguyenHoangSon96 Date: Fri, 12 Sep 2025 12:33:57 +0700 Subject: [PATCH 06/12] test: add test cases --- Client.Test.Integration/QueryWriteTest.cs | 52 ++++++----------------- 1 file changed, 12 insertions(+), 40 deletions(-) diff --git a/Client.Test.Integration/QueryWriteTest.cs b/Client.Test.Integration/QueryWriteTest.cs index 6bd2a37..1f18c56 100644 --- a/Client.Test.Integration/QueryWriteTest.cs +++ b/Client.Test.Integration/QueryWriteTest.cs @@ -169,30 +169,7 @@ public async Task MaxReceiveMessageSize() } [Test] - public void GrpcDeadline() - { - using var client = new InfluxDBClient(new ClientConfig - { - Host = Host, - Token = Token, - Database = Database, - QueryOptions = new QueryOptions() - { - Deadline = DateTime.UtcNow.AddMicroseconds(1) - } - }); - - var ex = Assert.ThrowsAsync(async () => - { - await foreach (var _ in client.Query("SELECT value FROM stat")) - { - } - }); - Assert.That(ex.StatusCode, Is.EqualTo(StatusCode.DeadlineExceeded)); - } - - [Test] - public Task TimeoutExceededByDeadline() + public async Task TimeoutExceededByDeadline() { using var client = new InfluxDBClient(new ClientConfig { @@ -203,18 +180,17 @@ public Task TimeoutExceededByDeadline() QueryTimeout = TimeSpan.FromSeconds(11), QueryOptions = new QueryOptions() { - Deadline = DateTime.UtcNow.AddMilliseconds(1) // Deadline will have a higher priority than QueryTimeout + Deadline = DateTime.UtcNow.AddTicks(1) // Deadline will have a higher priority than QueryTimeout } }); + await client.WriteRecordAsync("mem,tag=a field=1"); TestQuery(client); TestQueryBatches(client); TestQueryPoints(client); - - return Task.CompletedTask; } [Test] - public Task TimeoutExceededByQueryTimeout() + public async Task TimeoutExceededByQueryTimeout() { using var client = new InfluxDBClient(new ClientConfig { @@ -222,18 +198,16 @@ public Task TimeoutExceededByQueryTimeout() Token = Token, Database = Database, WriteTimeout = TimeSpan.FromSeconds(11), - QueryTimeout = TimeSpan.FromMilliseconds(1), + QueryTimeout = TimeSpan.FromTicks(1) }); + await client.WriteRecordAsync("mem,tag=a field=1"); TestQuery(client); TestQueryBatches(client); TestQueryPoints(client); - - return Task.CompletedTask; - } [Test] - public Task TimeoutExceeded() + public async Task TimeoutExceeded() { using var client = new InfluxDBClient(new ClientConfig { @@ -247,20 +221,18 @@ public Task TimeoutExceeded() Deadline = DateTime.UtcNow.AddSeconds(11), } }); - - var timeout = TimeSpan.FromMilliseconds(1); + await client.WriteRecordAsync("mem,tag=a field=1"); + var timeout = TimeSpan.FromTicks(1); TestQuery(client, timeout); TestQueryBatches(client, timeout); TestQueryPoints(client, timeout); - - return Task.FromResult(Task.CompletedTask); } private static void TestQuery(InfluxDBClient client, TimeSpan? timeout = null) { var ex = Assert.ThrowsAsync(async () => { - await foreach (var _ in client.Query("SELECT * FROM weathers LIMIT 5", timeout: timeout)) + await foreach (var _ in client.Query("SELECT * FROM mem", timeout: timeout)) { } }); @@ -271,7 +243,7 @@ private static void TestQueryBatches(InfluxDBClient client, TimeSpan? timeout = { var ex = Assert.ThrowsAsync(async () => { - await foreach (var _ in client.QueryBatches("SELECT * FROM weathers LIMIT 5", timeout: timeout)) + await foreach (var _ in client.QueryBatches("SELECT * FROM mem", timeout: timeout)) { } }); @@ -282,7 +254,7 @@ private static void TestQueryPoints(InfluxDBClient client, TimeSpan? timeout = n { var ex = Assert.ThrowsAsync(async () => { - await foreach (var _ in client.QueryPoints("SELECT * FROM weathers LIMIT 5", timeout: timeout)) + await foreach (var _ in client.QueryPoints("SELECT * FROM mem", timeout: timeout)) { } }); From 4ff38984796bac7250dd58d06c7168b0bbd8cfc7 Mon Sep 17 00:00:00 2001 From: NguyenHoangSon96 Date: Fri, 12 Sep 2025 12:39:40 +0700 Subject: [PATCH 07/12] chore: CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3776d69..f01a54d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Features 1. [#174](https://github.com/InfluxCommunity/influxdb3-csharp/pull/174): Support passing HttpClient to InfluxDBClient. +1. [#175](https://github.com/InfluxCommunity/influxdb3-csharp/pull/175): Add QueryTimeout and WriteTimeout to ClientConfig. ## 1.3.0 [2025-08-12] From c0d9e0c704a6cb60da164d7a661bcde537d7a15a Mon Sep 17 00:00:00 2001 From: NguyenHoangSon96 Date: Mon, 15 Sep 2025 13:52:03 +0700 Subject: [PATCH 08/12] fix: revert null to default --- Client.Test/InfluxDBClientWriteTest.cs | 14 ++++---- Client/InfluxDBClient.cs | 50 ++++++-------------------- 2 files changed, 18 insertions(+), 46 deletions(-) diff --git a/Client.Test/InfluxDBClientWriteTest.cs b/Client.Test/InfluxDBClientWriteTest.cs index 1683368..e4dc696 100644 --- a/Client.Test/InfluxDBClientWriteTest.cs +++ b/Client.Test/InfluxDBClientWriteTest.cs @@ -505,7 +505,7 @@ public void TimeoutExceededByTimeout() Host = MockServerUrl, Token = "my-token", Database = "my-database", - Timeout = TimeSpan.FromSeconds(1) + Timeout = TimeSpan.FromTicks(1) }); TestWriteRecordAsync(_client); TestWriteRecordsAsync(_client); @@ -527,7 +527,7 @@ public void TimeoutExceededByWriteTimeout() Database = "my-database", QueryTimeout = TimeSpan.FromSeconds(11), Timeout = TimeSpan.FromSeconds(11), - WriteTimeout = TimeSpan.FromSeconds(1) // WriteTimeout has a higher priority than Timeout + WriteTimeout = TimeSpan.FromTicks(1) // WriteTimeout has a higher priority than Timeout }); TestWriteRecordAsync(_client); TestWriteRecordsAsync(_client); @@ -552,7 +552,7 @@ public void TimeoutExceededByToken() Timeout = TimeSpan.FromSeconds(11), WriteTimeout = TimeSpan.FromSeconds(11) }); - var cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token; + var cancellationToken = new CancellationTokenSource(TimeSpan.FromTicks(1)).Token; TestWriteRecordAsync(_client, cancellationToken); TestWriteRecordsAsync(_client, cancellationToken); TestWritePointAsync(_client, cancellationToken); @@ -563,7 +563,7 @@ private static void TestWriteRecordAsync(InfluxDBClient client, CancellationToke { Assert.ThrowsAsync(async () => { - await client.WriteRecordAsync("mem,tag=a field=1", cancellationToken: cancellationToken); + await client.WriteRecordAsync("mem,tag=a field=1", cancellationToken: cancellationToken ?? CancellationToken.None);; }); } @@ -573,7 +573,7 @@ private static void TestWriteRecordsAsync(InfluxDBClient client, CancellationTok { await client.WriteRecordsAsync( records: new[] { "stat,unit=temperature value=24.5", "stat,unit=temperature value=25.5" }, - cancellationToken: cancellationToken + cancellationToken: cancellationToken ?? CancellationToken.None ); }); } @@ -584,7 +584,7 @@ private static void TestWritePointAsync(InfluxDBClient client, CancellationToken { await client.WritePointAsync( PointData.Measurement("h2o").SetTag("location", "europe").SetField("level", 2), - cancellationToken: cancellationToken + cancellationToken: cancellationToken ?? CancellationToken.None ); }); } @@ -599,7 +599,7 @@ await client.WritePointsAsync( PointData.Measurement("h2o").SetTag("location", "europe").SetField("level", 2), PointData.Measurement("h2o").SetTag("location", "us-west").SetField("level", 4), }, - cancellationToken: cancellationToken + cancellationToken: cancellationToken ?? CancellationToken.None ); }); } diff --git a/Client/InfluxDBClient.cs b/Client/InfluxDBClient.cs index 5948bc9..af6fb66 100644 --- a/Client/InfluxDBClient.cs +++ b/Client/InfluxDBClient.cs @@ -193,34 +193,7 @@ IAsyncEnumerable QueryPoints(string query, QueryType? queryType /// /// specifies the token to monitor for cancellation requests. Task WriteRecordAsync(string record, string? database = null, WritePrecision? precision = null, - Dictionary? headers = null, CancellationToken? cancellationToken = null); - - /// - /// Write data to InfluxDB. - /// - /// - /// - /// The following example shows how to write multiple records with custom headers: - /// - /// - /// using var client = new InfluxDBClient(host: "http://localhost:8086", token: "my-token", organization: "my-org", database: "my-database"); - /// - /// await client.WriteRecordsAsync( - /// records: new[] { "stat,unit=temperature value=24.5", "stat,unit=temperature value=25.5" }, - /// headers: new Dictionary<string, string> { { "X-Tracing-Id", "123" } } - /// ); - /// - /// - /// Specifies the records in InfluxDB Line Protocol. The is considered as one batch unit. - /// The database to be used for InfluxDB operations. - /// The to use for the timestamp in the write API call. - /// - /// The headers to be added to write request. The headers specified here are preferred over - /// the headers specified in the client configuration. - /// - /// specifies the token to monitor for cancellation requests. - Task WriteRecordsAsync(IEnumerable records, string? database = null, WritePrecision? precision = null, - Dictionary? headers = null, CancellationToken? cancellationToken = null); + Dictionary? headers = null, CancellationToken cancellationToken = default); /// /// Write data to InfluxDB. @@ -246,7 +219,7 @@ Task WriteRecordsAsync(IEnumerable records, string? database = null, Wri /// /// specifies the token to monitor for cancellation requests. Task WritePointAsync(PointData point, string? database = null, WritePrecision? precision = null, - Dictionary? headers = null, CancellationToken? cancellationToken = null); + Dictionary? headers = null, CancellationToken cancellationToken = default); /// /// Write data to InfluxDB. @@ -276,7 +249,7 @@ Task WritePointAsync(PointData point, string? database = null, WritePrecision? p /// /// specifies the token to monitor for cancellation requests. Task WritePointsAsync(IEnumerable points, string? database = null, WritePrecision? precision = null, - Dictionary? headers = null, CancellationToken? cancellationToken = null); + Dictionary? headers = null, CancellationToken cancellationToken = default); /// /// Retrieves the server version of the connected InfluxDB instance. @@ -647,7 +620,7 @@ public IAsyncEnumerable QueryBatches(string query, QueryType? query /// ); /// /// - /// + /// /// Specifies the record in InfluxDB Line Protocol. The is considered as one batch unit. /// The database to be used for InfluxDB operations. /// The to use for the timestamp in the write API call. @@ -657,7 +630,7 @@ public IAsyncEnumerable QueryBatches(string query, QueryType? query /// /// specifies the token to monitor for cancellation requests. public Task WriteRecordAsync(string record, string? database = null, WritePrecision? precision = null, - Dictionary? headers = null, CancellationToken? cancellationToken = null) + Dictionary? headers = null, CancellationToken cancellationToken = default) { return WriteRecordsAsync(new[] { record }, database, precision, headers, cancellationToken); } @@ -688,7 +661,7 @@ public Task WriteRecordAsync(string record, string? database = null, WritePrecis /// specifies the token to monitor for cancellation requests. public Task WriteRecordsAsync(IEnumerable records, string? database = null, WritePrecision? precision = null, Dictionary? headers = null, - CancellationToken? cancellationToken = null) + CancellationToken cancellationToken = default) { return WriteData(records, database, precision, headers, cancellationToken); } @@ -717,7 +690,7 @@ public Task WriteRecordsAsync(IEnumerable records, string? database = nu /// /// specifies the token to monitor for cancellation requests. public Task WritePointAsync(PointData point, string? database = null, WritePrecision? precision = null, - Dictionary? headers = null, CancellationToken? cancellationToken = null) + Dictionary? headers = null, CancellationToken cancellationToken = default) { return WritePointsAsync(new[] { point }, database, precision, headers, cancellationToken); } @@ -751,15 +724,14 @@ public Task WritePointAsync(PointData point, string? database = null, WritePreci /// specifies the token to monitor for cancellation requests. public Task WritePointsAsync(IEnumerable points, string? database = null, WritePrecision? precision = null, Dictionary? headers = null, - CancellationToken? cancellationToken = null) + CancellationToken cancellationToken = default) { return WriteData(points, database, precision, headers, cancellationToken); } private async Task WriteData(IEnumerable data, string? database = null, WritePrecision? precision = null, Dictionary? headers = null, - CancellationToken? cancellationToken = null) - + CancellationToken cancellationToken = default) { if (_disposed) { @@ -806,9 +778,9 @@ var databaseNotNull } var cancelToken = new CancellationTokenSource(_config.Timeout).Token; // Just for compatibility with the old API - if (cancellationToken.HasValue) + if (cancellationToken != CancellationToken.None) { - cancelToken = cancellationToken.Value; + cancelToken = cancellationToken; } else if (_config.WriteTimeout.HasValue) { From 21f7434ac339460035d15e6913fea11a8b325bf6 Mon Sep 17 00:00:00 2001 From: NguyenHoangSon96 Date: Mon, 15 Sep 2025 14:13:51 +0700 Subject: [PATCH 09/12] chore: dotnet format --- Client.Test/InfluxDBClientWriteTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client.Test/InfluxDBClientWriteTest.cs b/Client.Test/InfluxDBClientWriteTest.cs index e4dc696..a089e96 100644 --- a/Client.Test/InfluxDBClientWriteTest.cs +++ b/Client.Test/InfluxDBClientWriteTest.cs @@ -563,7 +563,7 @@ private static void TestWriteRecordAsync(InfluxDBClient client, CancellationToke { Assert.ThrowsAsync(async () => { - await client.WriteRecordAsync("mem,tag=a field=1", cancellationToken: cancellationToken ?? CancellationToken.None);; + await client.WriteRecordAsync("mem,tag=a field=1", cancellationToken: cancellationToken ?? CancellationToken.None); }); } From f88e28d43018f7ff07076a33f517dd6edb913543 Mon Sep 17 00:00:00 2001 From: NguyenHoangSon96 Date: Mon, 15 Sep 2025 14:43:09 +0700 Subject: [PATCH 10/12] [EMPTY] trigger CI From 91825243523d12d9fe2ee079aa6e426a8e7b0a79 Mon Sep 17 00:00:00 2001 From: NguyenHoangSon96 Date: Mon, 15 Sep 2025 14:52:58 +0700 Subject: [PATCH 11/12] [EMPTY] trigger CI From e811c69d01c2ce84d215b18aafd562c132629ad6 Mon Sep 17 00:00:00 2001 From: NguyenHoangSon96 Date: Mon, 15 Sep 2025 15:00:23 +0700 Subject: [PATCH 12/12] test: improve WriteTest --- Client.Test.Integration/WriteTest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Client.Test.Integration/WriteTest.cs b/Client.Test.Integration/WriteTest.cs index 328b7be..5ddb051 100644 --- a/Client.Test.Integration/WriteTest.cs +++ b/Client.Test.Integration/WriteTest.cs @@ -33,6 +33,7 @@ public async Task WriteWithError() Assert.That(iaex.Message, Does.Contain("Found trailing content") .Or.Contain("partial write of line protocol occurred") + .Or.Contain("write buffer error: parsing for line protocol failed") ); Assert.That(iaex.StatusCode.ToString(), Is.EqualTo("BadRequest")); Assert.That(iaex.StatusCode, Is.EqualTo(HttpStatusCode.BadRequest));