From e147c98afa52396e41bb8cdcd1ab317b20403d57 Mon Sep 17 00:00:00 2001 From: karel rehor Date: Fri, 16 Aug 2024 16:26:30 +0200 Subject: [PATCH 01/11] feat: (WIP) add response headers to HttpException --- Client.Core/Exceptions/InfluxException.cs | 7 ++++ Client.Test/InfluxExceptionTest.cs | 51 +++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 Client.Test/InfluxExceptionTest.cs diff --git a/Client.Core/Exceptions/InfluxException.cs b/Client.Core/Exceptions/InfluxException.cs index d413f25c5..dcfe774db 100644 --- a/Client.Core/Exceptions/InfluxException.cs +++ b/Client.Core/Exceptions/InfluxException.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Net; using System.Net.Http; +using System.Net.Http.Headers; using InfluxDB.Client.Core.Internal; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -56,6 +57,11 @@ public HttpException(string message, int status, Exception exception = null) : b /// public int? RetryAfter { get; set; } + /// + /// The response headers + /// + public IEnumerable Headers; + public static HttpException Create(RestResponse requestResult, object body) { Arguments.CheckNotNull(requestResult, nameof(requestResult)); @@ -162,6 +168,7 @@ public static HttpException Create(object content, IEnumerable err.ErrorBody = errorBody; err.RetryAfter = retryAfter; + err.Headers = headers; return err; } diff --git a/Client.Test/InfluxExceptionTest.cs b/Client.Test/InfluxExceptionTest.cs new file mode 100644 index 000000000..65326c827 --- /dev/null +++ b/Client.Test/InfluxExceptionTest.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using InfluxDB.Client.Core.Exceptions; +using Newtonsoft.Json.Linq; +using NUnit.Framework; +using RestSharp; + +namespace InfluxDB.Client.Test +{ + [TestFixture] + public class InfluxExceptionTest + { + [Test] + public void ExceptionHeadersTest() + { + try + { + throw HttpException.Create( + JObject.Parse("{\"callId\": \"123456789\", \"message\": \"error in content object\"}"), + new List + { + new HeaderParameter("Trace-Id", "123456789ABCDEF0"), + new HeaderParameter("X-Influx-Version", "1.0.0"), + new HeaderParameter("X-Platform-Error-Code", "unavailable"), + new HeaderParameter("Retry-After", "60000"), + }, + null, + HttpStatusCode.ServiceUnavailable); + } + catch (HttpException he) + { + // Assert.AreEqual("error in content object", he?.Message); + Console.WriteLine("DEBUG he.Message {0}", he.Message); + + + Assert.AreEqual(4, he?.Headers.Count()); + Dictionary headers = new Dictionary(); + foreach (HeaderParameter header in he?.Headers) + { + headers.Add(header.Name, header.Value); + } + Assert.AreEqual("123456789ABCDEF0", headers["Trace-Id"]); + Assert.AreEqual("1.0.0", headers["X-Influx-Version"]); + Assert.AreEqual("unavailable", headers["X-Platform-Error-Code"]); + Assert.AreEqual("60000", headers["Retry-After"]); + } + } + } +} \ No newline at end of file From cf99eb6b8f0c5de477eacd2f14a9eba66d62f81e Mon Sep 17 00:00:00 2001 From: karel rehor Date: Fri, 16 Aug 2024 16:40:35 +0200 Subject: [PATCH 02/11] chore: (WIP) reformat test code --- Client.Test/InfluxExceptionTest.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/Client.Test/InfluxExceptionTest.cs b/Client.Test/InfluxExceptionTest.cs index 65326c827..2c7e6a73c 100644 --- a/Client.Test/InfluxExceptionTest.cs +++ b/Client.Test/InfluxExceptionTest.cs @@ -24,23 +24,18 @@ public void ExceptionHeadersTest() new HeaderParameter("Trace-Id", "123456789ABCDEF0"), new HeaderParameter("X-Influx-Version", "1.0.0"), new HeaderParameter("X-Platform-Error-Code", "unavailable"), - new HeaderParameter("Retry-After", "60000"), + new HeaderParameter("Retry-After", "60000") }, null, HttpStatusCode.ServiceUnavailable); } catch (HttpException he) { - // Assert.AreEqual("error in content object", he?.Message); - Console.WriteLine("DEBUG he.Message {0}", he.Message); - - + Assert.AreEqual("error in content object", he?.Message); + Assert.AreEqual(4, he?.Headers.Count()); - Dictionary headers = new Dictionary(); - foreach (HeaderParameter header in he?.Headers) - { - headers.Add(header.Name, header.Value); - } + var headers = new Dictionary(); + foreach (var header in he?.Headers) headers.Add(header.Name, header.Value); Assert.AreEqual("123456789ABCDEF0", headers["Trace-Id"]); Assert.AreEqual("1.0.0", headers["X-Influx-Version"]); Assert.AreEqual("unavailable", headers["X-Platform-Error-Code"]); From 888fb5962c8bd56937e74bf0fb8b1412bbf169fa Mon Sep 17 00:00:00 2001 From: karel rehor Date: Wed, 28 Aug 2024 10:40:03 +0200 Subject: [PATCH 03/11] feat: (WIP) makes response headers accessible from WriteErrorEvent --- Client.Test/ItErrorEventsTest.cs | 104 +++++++++++++++++++++++++++++ Client.Test/ItWriteApiAsyncTest.cs | 25 +++++++ Client.Test/WriteApiTest.cs | 57 ++++++++++++++++ Client/Writes/Events.cs | 8 +++ 4 files changed, 194 insertions(+) create mode 100644 Client.Test/ItErrorEventsTest.cs diff --git a/Client.Test/ItErrorEventsTest.cs b/Client.Test/ItErrorEventsTest.cs new file mode 100644 index 000000000..6bc8b2ecc --- /dev/null +++ b/Client.Test/ItErrorEventsTest.cs @@ -0,0 +1,104 @@ +using System; +using NUnit.Framework; +using System.Collections.Generic; +using System.Threading.Tasks; + +using InfluxDB.Client.Api.Domain; +using InfluxDB.Client.Writes; + +namespace InfluxDB.Client.Test +{ + [TestFixture] + public class ItErrorEventsTest : AbstractItClientTest + { + private Organization _org; + private Bucket _bucket; + private string _token; + private InfluxDBClientOptions _options; + + [SetUp] + public new async Task SetUp() + { + _org = await FindMyOrg(); + _bucket = await Client.GetBucketsApi() + .CreateBucketAsync(GenerateName("fliers"), null, _org); + + // + // Add Permissions to read and write to the Bucket + // + var resource = new PermissionResource(PermissionResource.TypeBuckets, _bucket.Id, null, + _org.Id); + + var readBucket = new Permission(Permission.ActionEnum.Read, resource); + var writeBucket = new Permission(Permission.ActionEnum.Write, resource); + + var loggedUser = await Client.GetUsersApi().MeAsync(); + Assert.IsNotNull(loggedUser); + + var authorization = await Client.GetAuthorizationsApi() + .CreateAuthorizationAsync(_org, + new List { readBucket, writeBucket }); + + _token = authorization.Token; + + Client.Dispose(); + + _options = new InfluxDBClientOptions(InfluxDbUrl) + { + Token = _token, + Org = _org.Id, + Bucket = _bucket.Id + }; + + Client = new InfluxDBClient(_options); + } + + + [Test] + public void HandleEvents() + { + using (var writeApi = Client.GetWriteApi()) + { + writeApi.EventHandler += (sender, eventArgs) => + { + switch (eventArgs) + { + case WriteSuccessEvent successEvent: + Assert.Fail("Call should not succeed"); + break; + case WriteErrorEvent errorEvent: + Assert.AreEqual("unable to parse 'velocity,unit=C3PO mps=': missing field value", + errorEvent.Exception.Message); + var eventHeaders = errorEvent.GetHeaders(); + if (eventHeaders == null) + { + Assert.Fail("WriteErrorEvent must return headers."); + } + + var headers = new Dictionary {}; + foreach (var hp in eventHeaders) + { + Console.WriteLine("DEBUG {0}: {1}", hp.Name, hp.Value); + headers.Add(hp.Name, hp.Value); + } + + Assert.AreEqual(4, headers.Count); + Assert.AreEqual("OSS", headers["X-Influxdb-Build"]); + Assert.True(headers["X-Influxdb-Version"].StartsWith('v')); + Assert.AreEqual("invalid", headers["X-Platform-Error-Code"]); + Assert.AreNotEqual("missing", headers.GetValueOrDefault("Date", "missing")); + break; + case WriteRetriableErrorEvent retriableErrorEvent: + Assert.Fail("Call should not be retriable."); + break; + case WriteRuntimeExceptionEvent runtimeExceptionEvent: + Assert.Fail("Call should not result in runtime exception. {0}", runtimeExceptionEvent); + break; + } + }; + + writeApi.WriteRecord("velocity,unit=C3PO mps=", WritePrecision.S, _bucket.Name, _org.Name); + } + } + } +} \ No newline at end of file diff --git a/Client.Test/ItWriteApiAsyncTest.cs b/Client.Test/ItWriteApiAsyncTest.cs index 6cfb6323e..a9aba7798 100644 --- a/Client.Test/ItWriteApiAsyncTest.cs +++ b/Client.Test/ItWriteApiAsyncTest.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Threading.Tasks; using InfluxDB.Client.Api.Domain; using InfluxDB.Client.Core; +using InfluxDB.Client.Core.Exceptions; using InfluxDB.Client.Core.Flux.Domain; using InfluxDB.Client.Core.Test; using InfluxDB.Client.Writes; @@ -185,5 +187,28 @@ public async Task WriteULongValues() Assert.AreEqual(ulong.MaxValue, query[0].Records[0].GetValue()); } + + [Test] + public async Task WriteWithError() + { + try + { + await _writeApi.WriteRecordAsync("h2o,location=fox_hollow water_level="); + Assert.Fail("Call should fail"); + } + catch (HttpException exception) + { + Assert.AreEqual("unable to parse 'h2o,location=fox_hollow water_level=': missing field value", + exception.Message); + Assert.AreEqual(400, exception.Status); + Assert.GreaterOrEqual(4, exception.Headers.Count()); + var headers = new Dictionary(); + foreach (var header in exception?.Headers) headers.Add(header.Name, header.Value); + Assert.AreEqual("OSS", headers["X-Influxdb-Build"]); + Assert.AreEqual("invalid", headers["X-Platform-Error-Code"]); + Assert.IsTrue(headers["X-Influxdb-Version"].StartsWith('v')); + Assert.NotNull(headers["Date"]); + } + } } } \ No newline at end of file diff --git a/Client.Test/WriteApiTest.cs b/Client.Test/WriteApiTest.cs index ec2b3fc3a..0eff71ef5 100644 --- a/Client.Test/WriteApiTest.cs +++ b/Client.Test/WriteApiTest.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Threading; +using Castle.Core.Smtp; using InfluxDB.Client.Api.Domain; using InfluxDB.Client.Core; using InfluxDB.Client.Core.Exceptions; @@ -506,6 +507,62 @@ public void WriteRuntimeException() Assert.AreEqual(0, MockServer.LogEntries.Count()); } + [Test] + public void WriteExceptionWithHeaders() + { + var localWriteApi = _client.GetWriteApi(new WriteOptions { RetryInterval = 1_000 }); + + var traceId = Guid.NewGuid().ToString(); + const string buildName = "TestBuild"; + const string version = "v99.9.9"; + + localWriteApi.EventHandler += (sender, eventArgs) => + { + switch (eventArgs) + { + case WriteErrorEvent errorEvent: + Assert.AreEqual("just a test", errorEvent.Exception.Message); + var errHeaders = errorEvent.GetHeaders(); + var headers = new Dictionary(); + foreach (var h in errHeaders) + headers.Add(h.Name, h.Value); + Assert.AreEqual(6, headers.Count); + Assert.AreEqual(traceId, headers["Trace-Id"]); + Assert.AreEqual(buildName, headers["X-Influxdb-Build"]); + Assert.AreEqual(version, headers["X-Influxdb-Version"]); + break; + default: + Assert.Fail("Expect only WriteErrorEvents but got {0}", eventArgs.GetType()); + break; + } + }; + MockServer + .Given(Request.Create().WithPath("/api/v2/write").UsingPost()) + .RespondWith( + CreateResponse("{ \"message\": \"just a test\", \"status-code\": \"Bad Request\"}") + .WithStatusCode(400) + .WithHeaders(new Dictionary() + { + {"Content-Type", "application/json"}, + {"Trace-Id", traceId}, + {"X-Influxdb-Build", buildName}, + {"X-Influxdb-Version", version}, + }) + ); + + + var measurement = new SimpleModel + { + Time = new DateTime(2024, 09, 01, 6, 15, 00), + Device = "R2D2", + Value = 1976 + }; + + localWriteApi.WriteMeasurement(measurement, WritePrecision.S, "b1", "org1"); + + localWriteApi.Dispose(); + } + [Test] public void RequiredOrgBucketWriteApi() { diff --git a/Client/Writes/Events.cs b/Client/Writes/Events.cs index 14ae98db8..22f638f2a 100644 --- a/Client/Writes/Events.cs +++ b/Client/Writes/Events.cs @@ -1,7 +1,10 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using InfluxDB.Client.Api.Domain; using InfluxDB.Client.Core; +using InfluxDB.Client.Core.Exceptions; +using RestSharp; namespace InfluxDB.Client.Writes { @@ -42,6 +45,11 @@ internal override void LogEvent() { Trace.TraceError($"The error occurred during writing of data: {Exception.Message}"); } + + public IEnumerable GetHeaders() + { + return ((HttpException)Exception)?.Headers; + } } /// From 6ed10dca78cfc7dae0b5067f94cd68d52016ec84 Mon Sep 17 00:00:00 2001 From: karel rehor Date: Wed, 28 Aug 2024 11:02:14 +0200 Subject: [PATCH 04/11] chore: reformat code in recent changes. --- Client.Test/ItErrorEventsTest.cs | 7 +++---- Client.Test/WriteApiTest.cs | 10 +++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Client.Test/ItErrorEventsTest.cs b/Client.Test/ItErrorEventsTest.cs index 6bc8b2ecc..e604200a5 100644 --- a/Client.Test/ItErrorEventsTest.cs +++ b/Client.Test/ItErrorEventsTest.cs @@ -2,7 +2,6 @@ using NUnit.Framework; using System.Collections.Generic; using System.Threading.Tasks; - using InfluxDB.Client.Api.Domain; using InfluxDB.Client.Writes; @@ -67,7 +66,7 @@ public void HandleEvents() Assert.Fail("Call should not succeed"); break; case WriteErrorEvent errorEvent: - Assert.AreEqual("unable to parse 'velocity,unit=C3PO mps=': missing field value", + Assert.AreEqual("unable to parse 'velocity,unit=C3PO mps=': missing field value", errorEvent.Exception.Message); var eventHeaders = errorEvent.GetHeaders(); if (eventHeaders == null) @@ -75,7 +74,7 @@ public void HandleEvents() Assert.Fail("WriteErrorEvent must return headers."); } - var headers = new Dictionary {}; + var headers = new Dictionary { }; foreach (var hp in eventHeaders) { Console.WriteLine("DEBUG {0}: {1}", hp.Name, hp.Value); @@ -99,6 +98,6 @@ public void HandleEvents() writeApi.WriteRecord("velocity,unit=C3PO mps=", WritePrecision.S, _bucket.Name, _org.Name); } - } + } } } \ No newline at end of file diff --git a/Client.Test/WriteApiTest.cs b/Client.Test/WriteApiTest.cs index 0eff71ef5..29d3212b4 100644 --- a/Client.Test/WriteApiTest.cs +++ b/Client.Test/WriteApiTest.cs @@ -507,7 +507,7 @@ public void WriteRuntimeException() Assert.AreEqual(0, MockServer.LogEntries.Count()); } - [Test] + [Test] public void WriteExceptionWithHeaders() { var localWriteApi = _client.GetWriteApi(new WriteOptions { RetryInterval = 1_000 }); @@ -543,10 +543,10 @@ public void WriteExceptionWithHeaders() .WithStatusCode(400) .WithHeaders(new Dictionary() { - {"Content-Type", "application/json"}, - {"Trace-Id", traceId}, - {"X-Influxdb-Build", buildName}, - {"X-Influxdb-Version", version}, + { "Content-Type", "application/json" }, + { "Trace-Id", traceId }, + { "X-Influxdb-Build", buildName }, + { "X-Influxdb-Version", version } }) ); From 652fcf64562d55099a1a51a21a81f0524e424212 Mon Sep 17 00:00:00 2001 From: karel rehor Date: Wed, 28 Aug 2024 15:03:31 +0200 Subject: [PATCH 05/11] docs: adds examples of handling HTTP Headers in errors. --- Examples/HttpErrorHandling.cs | 122 ++++++++++++++++++++++++++++++++++ Examples/RunExamples.cs | 3 + 2 files changed, 125 insertions(+) create mode 100644 Examples/HttpErrorHandling.cs diff --git a/Examples/HttpErrorHandling.cs b/Examples/HttpErrorHandling.cs new file mode 100644 index 000000000..7e4c12af2 --- /dev/null +++ b/Examples/HttpErrorHandling.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using InfluxDB.Client; +using InfluxDB.Client.Api.Domain; +using InfluxDB.Client.Core.Exceptions; +using InfluxDB.Client.Writes; +using RestSharp; + +namespace Examples +{ + public class HttpErrorHandling + { + private static InfluxDBClient _client; + private static List _lpRecords; + + private static void Setup() + { + _client = new InfluxDBClient("http://localhost:9999", + "my-user", "my-password"); + var nowMillis = DateTimeOffset.Now.ToUnixTimeMilliseconds(); + + _lpRecords = new List() + { + $"temperature,location=north value=42 {nowMillis}", + $"temperature,location=north value=17 {nowMillis - 10000}", + $"temperature,location=north value= {nowMillis - 20000}", // one flaky record + $"temperature,location=north value=5 {nowMillis - 30000}" + }; + } + + private static void TearDown() + { + _client.Dispose(); + } + + private static Dictionary Headers2Dictionary(IEnumerable headers) + { + var result = new Dictionary(); + foreach (var hp in headers) + result.Add(hp.Name, hp.Value); + return result; + } + + private static async Task WriteRecordsAsync() + { + Console.WriteLine("Write records async with one invalid record."); + + // + // Write Data + // + var writeApiAsync = _client.GetWriteApiAsync(); + + try + { + await writeApiAsync.WriteRecordsAsync(_lpRecords, WritePrecision.Ms, + "my-bucket", "my-org"); + } + catch (HttpException he) + { + Console.WriteLine(" WARNING write failed"); + var headersDix = Headers2Dictionary(he.Headers); + Console.WriteLine(" Caught Exception({0}) {1} with the following headers:", + he.GetType(), + he.Message); + foreach (var key in headersDix.Keys) + Console.WriteLine($" {key}: {headersDix[key]}"); + } + finally + { + Console.WriteLine(" ===================="); + } + } + + private static void WriteRecordsWithErrorEvent() + { + Console.WriteLine("Write records with error event."); + + var caughtErrorCount = 0; + using (var writeApi = _client.GetWriteApi()) + { + writeApi.EventHandler += (sender, eventArgs) => + { + switch (eventArgs) + { + case WriteErrorEvent wee: + Console.WriteLine(" WARNING write failed"); + Console.WriteLine(" Received event WriteErrorEvent with:"); + Console.WriteLine(" Status: {0}", ((HttpException)wee.Exception).Status); + Console.WriteLine(" Exception: {0}", wee.Exception.GetType()); + Console.WriteLine(" Message: {0}", wee.Exception.Message); + Console.WriteLine(" Headers:"); + var headersDix = Headers2Dictionary(wee.GetHeaders()); + foreach (var key in headersDix.Keys) + Console.WriteLine($" {key}: {headersDix[key]}"); + caughtErrorCount++; + break; + default: + throw new Exception("Should only receive WriteErrorEvent"); + } + }; + Console.WriteLine("Trying the records list"); + writeApi.WriteRecords(_lpRecords, WritePrecision.Ms, "my-bucket", "my-org"); + while (caughtErrorCount == 0) Thread.Sleep(1000); + // manually retry the bad record + Console.WriteLine("Manually retrying the bad record."); + writeApi.WriteRecord(_lpRecords[2], WritePrecision.Ms, "my-bucket", "my-org"); + while (caughtErrorCount == 1) Thread.Sleep(1000); + } + } + + public static async Task Main() + { + Console.WriteLine("Main()"); + Setup(); + await WriteRecordsAsync(); + WriteRecordsWithErrorEvent(); + TearDown(); + } + } +} \ No newline at end of file diff --git a/Examples/RunExamples.cs b/Examples/RunExamples.cs index 91d5e59f8..a40688819 100644 --- a/Examples/RunExamples.cs +++ b/Examples/RunExamples.cs @@ -72,6 +72,9 @@ public static async Task Main(string[] args) case "RecordRowExample": await RecordRowExample.Main(); break; + case "HttpErrorHandling": + await HttpErrorHandling.Main(); + break; } } else From 4f9604b25ab722b37cc823104bef8b6472dfb1dc Mon Sep 17 00:00:00 2001 From: karel rehor Date: Wed, 28 Aug 2024 15:25:33 +0200 Subject: [PATCH 06/11] chore: tweak wait polling in new example. --- Examples/HttpErrorHandling.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Examples/HttpErrorHandling.cs b/Examples/HttpErrorHandling.cs index 7e4c12af2..fc967d069 100644 --- a/Examples/HttpErrorHandling.cs +++ b/Examples/HttpErrorHandling.cs @@ -102,11 +102,25 @@ private static void WriteRecordsWithErrorEvent() }; Console.WriteLine("Trying the records list"); writeApi.WriteRecords(_lpRecords, WritePrecision.Ms, "my-bucket", "my-org"); - while (caughtErrorCount == 0) Thread.Sleep(1000); + var slept = 0; + while (caughtErrorCount == 0 && slept < 3001) slept += 1000; + Thread.Sleep(1000); + if (slept > 3000) + { + Console.WriteLine("WARN, did not encounter expected error"); + } + + // manually retry the bad record Console.WriteLine("Manually retrying the bad record."); writeApi.WriteRecord(_lpRecords[2], WritePrecision.Ms, "my-bucket", "my-org"); - while (caughtErrorCount == 1) Thread.Sleep(1000); + slept = 0; + while (caughtErrorCount == 1 && slept < 3001) slept += 1000; + Thread.Sleep(1000); + if (slept > 3000) + { + Console.WriteLine("WARN, did not encounter expected error"); + } } } From ed14a8fc586bfcc55f5069dd27b63980e1d52828 Mon Sep 17 00:00:00 2001 From: karel rehor Date: Wed, 28 Aug 2024 16:42:53 +0200 Subject: [PATCH 07/11] docs: add API doc and update Examples/README.md --- Client/Writes/Events.cs | 3 +++ Examples/README.md | 1 + 2 files changed, 4 insertions(+) diff --git a/Client/Writes/Events.cs b/Client/Writes/Events.cs index 22f638f2a..dd8b32227 100644 --- a/Client/Writes/Events.cs +++ b/Client/Writes/Events.cs @@ -46,6 +46,9 @@ internal override void LogEvent() Trace.TraceError($"The error occurred during writing of data: {Exception.Message}"); } + /// + /// Get headers from the nested exception. + /// public IEnumerable GetHeaders() { return ((HttpException)Exception)?.Headers; diff --git a/Examples/README.md b/Examples/README.md index 6eca76b7a..e8681b3f4 100644 --- a/Examples/README.md +++ b/Examples/README.md @@ -2,6 +2,7 @@ ## Writes - [WriteEventHandlerExample.cs](WriteEventHandlerExample.cs) - How to use WriteAPI with batch options and how to handle events +- [HttpErrorHandling.cs](HttpErrorHandling.cs) - How to handle errors on write and retrieve response headers. ## Others - [InvokableScripts.cs](InvokableScripts.cs) - How to use Invokable scripts Cloud API to create custom endpoints that query data From 2b49ff561ffd85ac0016408d100e86d7ba2d9944 Mon Sep 17 00:00:00 2001 From: karel rehor Date: Wed, 28 Aug 2024 17:14:39 +0200 Subject: [PATCH 08/11] docs: tweaking new example. --- Examples/HttpErrorHandling.cs | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/Examples/HttpErrorHandling.cs b/Examples/HttpErrorHandling.cs index fc967d069..3c1f3fc80 100644 --- a/Examples/HttpErrorHandling.cs +++ b/Examples/HttpErrorHandling.cs @@ -61,11 +61,13 @@ await writeApiAsync.WriteRecordsAsync(_lpRecords, WritePrecision.Ms, { Console.WriteLine(" WARNING write failed"); var headersDix = Headers2Dictionary(he.Headers); - Console.WriteLine(" Caught Exception({0}) {1} with the following headers:", + Console.WriteLine(" Caught Exception({0}) \"{1}\"", he.GetType(), he.Message); + Console.WriteLine(" Response Status: {0}", he.Status); + Console.WriteLine(" Headers:"); foreach (var key in headersDix.Keys) - Console.WriteLine($" {key}: {headersDix[key]}"); + Console.WriteLine($" {key}: {headersDix[key]}"); } finally { @@ -77,7 +79,7 @@ private static void WriteRecordsWithErrorEvent() { Console.WriteLine("Write records with error event."); - var caughtErrorCount = 0; + var caughtError = false; using (var writeApi = _client.GetWriteApi()) { writeApi.EventHandler += (sender, eventArgs) => @@ -94,7 +96,7 @@ private static void WriteRecordsWithErrorEvent() var headersDix = Headers2Dictionary(wee.GetHeaders()); foreach (var key in headersDix.Keys) Console.WriteLine($" {key}: {headersDix[key]}"); - caughtErrorCount++; + caughtError = true; break; default: throw new Exception("Should only receive WriteErrorEvent"); @@ -103,9 +105,13 @@ private static void WriteRecordsWithErrorEvent() Console.WriteLine("Trying the records list"); writeApi.WriteRecords(_lpRecords, WritePrecision.Ms, "my-bucket", "my-org"); var slept = 0; - while (caughtErrorCount == 0 && slept < 3001) slept += 1000; - Thread.Sleep(1000); - if (slept > 3000) + while (!caughtError && slept < 3001) + { + Thread.Sleep(1000); + slept += 1000; + } + + if (!caughtError) { Console.WriteLine("WARN, did not encounter expected error"); } @@ -114,10 +120,15 @@ private static void WriteRecordsWithErrorEvent() // manually retry the bad record Console.WriteLine("Manually retrying the bad record."); writeApi.WriteRecord(_lpRecords[2], WritePrecision.Ms, "my-bucket", "my-org"); + caughtError = false; slept = 0; - while (caughtErrorCount == 1 && slept < 3001) slept += 1000; - Thread.Sleep(1000); - if (slept > 3000) + while (!caughtError && slept < 3001) + { + Thread.Sleep(1000); + slept += 1000; + } + + if (!caughtError) { Console.WriteLine("WARN, did not encounter expected error"); } From 94ac2a7fdbfd34a8abbef0c3bdce699bb50b00b7 Mon Sep 17 00:00:00 2001 From: karel rehor Date: Thu, 29 Aug 2024 10:29:41 +0200 Subject: [PATCH 09/11] docs: update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08ba5b2a5..3c9a1010d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## 4.18.0 [unreleased] +### Features: + - [#658](https://github.com/influxdata/influxdb-client-csharp/pull/658): Add HttpHeaders as `IEnumerable` to `HttpException` and facilitate access in `WriteErrorEvent`. Includes new example `HttpErrorHandling`. + ## 4.17.0 [2024-08-12] ### Breaking Changes From b855896406e1bfa27a47f8c7cf0bd6d9e63c2fcb Mon Sep 17 00:00:00 2001 From: karel rehor Date: Thu, 29 Aug 2024 10:47:51 +0200 Subject: [PATCH 10/11] chore: change Headers from raw field to AutoProperty --- Client.Core/Exceptions/InfluxException.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client.Core/Exceptions/InfluxException.cs b/Client.Core/Exceptions/InfluxException.cs index dcfe774db..b15bb6cf6 100644 --- a/Client.Core/Exceptions/InfluxException.cs +++ b/Client.Core/Exceptions/InfluxException.cs @@ -60,7 +60,7 @@ public HttpException(string message, int status, Exception exception = null) : b /// /// The response headers /// - public IEnumerable Headers; + public IEnumerable? Headers { get; private set; } public static HttpException Create(RestResponse requestResult, object body) { From 4b27cf072e7f0c81b953f672bd9fbfe90d86f39a Mon Sep 17 00:00:00 2001 From: karel rehor Date: Thu, 29 Aug 2024 11:13:13 +0200 Subject: [PATCH 11/11] chore: explicitly set nullable context for Headers. --- Client.Core/Exceptions/InfluxException.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Client.Core/Exceptions/InfluxException.cs b/Client.Core/Exceptions/InfluxException.cs index b15bb6cf6..ef679c58b 100644 --- a/Client.Core/Exceptions/InfluxException.cs +++ b/Client.Core/Exceptions/InfluxException.cs @@ -57,10 +57,12 @@ public HttpException(string message, int status, Exception exception = null) : b /// public int? RetryAfter { get; set; } +#nullable enable /// /// The response headers /// public IEnumerable? Headers { get; private set; } +#nullable disable public static HttpException Create(RestResponse requestResult, object body) { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy