protected internal InfluxDBClient(InfluxDBClientOptions options) { Arguments.CheckNotNull(options, nameof(options)); _options = options; _loggingHandler = new LoggingHandler(options.LogLevel); _gzipHandler = new GzipHandler(); var version = AssemblyHelper.GetVersion(typeof(InfluxDBClient)); _apiClient = new ApiClient(options, _loggingHandler, _gzipHandler); _apiClient.RestClient.UserAgent = $"influxdb-client-csharp/{version}"; _exceptionFactory = (methodName, response) => !response.IsSuccessful ? HttpException.Create(response, response.Content) : null; _setupService = new SetupService((Configuration)_apiClient.Configuration) { ExceptionFactory = _exceptionFactory }; _healthService = new HealthService((Configuration)_apiClient.Configuration) { ExceptionFactory = _exceptionFactory }; _readyService = new ReadyService((Configuration)_apiClient.Configuration) { ExceptionFactory = _exceptionFactory }; }
protected internal InfluxDBClient(InfluxDBClientOptions options) { Arguments.CheckNotNull(options, nameof(options)); _options = options; _loggingHandler = new LoggingHandler(options.LogLevel); _gzipHandler = new GzipHandler(); _apiClient = new ApiClient(options, _loggingHandler, _gzipHandler); _exceptionFactory = (methodName, response) => !response.IsSuccessful ? HttpException.Create(response) : null; _setupService = new SetupService((Configuration)_apiClient.Configuration) { ExceptionFactory = _exceptionFactory }; _healthService = new HealthService((Configuration)_apiClient.Configuration) { ExceptionFactory = _exceptionFactory }; _readyService = new ReadyService((Configuration)_apiClient.Configuration) { ExceptionFactory = _exceptionFactory }; }
protected void RaiseForInfluxError(object result, object body) { if (result is IRestResponse restResponse) { if (restResponse.IsSuccessful) { return; } if (restResponse.ErrorException is InfluxException) { throw restResponse.ErrorException; } throw HttpException.Create(restResponse, body); } var httpResponse = (IHttpResponse)result; if ((int)httpResponse.StatusCode >= 200 && (int)httpResponse.StatusCode < 300) { return; } if (httpResponse.ErrorException is InfluxException) { throw httpResponse.ErrorException; } throw HttpException.Create(httpResponse, body); }
private HttpException CreateException(int retryAfter = 10) { var headers = new List <HttpHeader> { new HttpHeader("Retry-After", retryAfter.ToString()) }; var exception = HttpException.Create("", headers, "", HttpStatusCode.TooManyRequests); return(exception); }
public void ExceptionTypes() { Assert.IsInstanceOf(typeof(BadRequestException), HttpException.Create(Response(400), "")); Assert.IsInstanceOf(typeof(UnauthorizedException), HttpException.Create(Response(401), "")); Assert.IsInstanceOf(typeof(PaymentRequiredException), HttpException.Create(Response(402), "")); Assert.IsInstanceOf(typeof(ForbiddenException), HttpException.Create(Response(403), "")); Assert.IsInstanceOf(typeof(NotFoundException), HttpException.Create(Response(404), "")); Assert.IsInstanceOf(typeof(MethodNotAllowedException), HttpException.Create(Response(405), "")); Assert.IsInstanceOf(typeof(NotAcceptableException), HttpException.Create(Response(406), "")); Assert.IsInstanceOf(typeof(ProxyAuthenticationRequiredException), HttpException.Create(Response(407), "")); Assert.IsInstanceOf(typeof(RequestTimeoutException), HttpException.Create(Response(408), "")); Assert.IsInstanceOf(typeof(RequestEntityTooLargeException), HttpException.Create(Response(413), "")); Assert.IsInstanceOf(typeof(UnprocessableEntityException), HttpException.Create(Response(422), "")); Assert.IsInstanceOf(typeof(TooManyRequestsException), HttpException.Create(Response(429), "")); Assert.IsInstanceOf(typeof(InternalServerErrorException), HttpException.Create(Response(500), "")); Assert.IsInstanceOf(typeof(HttpNotImplementedException), HttpException.Create(Response(501), "")); Assert.IsInstanceOf(typeof(BadGatewayException), HttpException.Create(Response(502), "")); Assert.IsInstanceOf(typeof(ServiceUnavailableException), HttpException.Create(Response(503), "")); Assert.IsInstanceOf(typeof(HttpException), HttpException.Create(Response(550), "")); Assert.IsInstanceOf(typeof(HttpException), HttpException.Create(Response(390), "")); }
protected internal WriteApi(InfluxDBClientOptions options, WriteService service, WriteOptions writeOptions, InfluxDBClient influxDbClient) { Arguments.CheckNotNull(service, nameof(service)); Arguments.CheckNotNull(writeOptions, nameof(writeOptions)); Arguments.CheckNotNull(influxDbClient, nameof(_influxDbClient)); _options = options; _influxDbClient = influxDbClient; // backpreasure - is not implemented in C# // // => use unbound buffer // // https://github.com/dotnet/reactive/issues/19 var observable = _subject.ObserveOn(writeOptions.WriteScheduler); var boundary = observable .Buffer(TimeSpan.FromMilliseconds(writeOptions.FlushInterval), writeOptions.BatchSize, writeOptions.WriteScheduler) .Merge(_flush); observable // // Batching // .Window(boundary) // // Group by key - same bucket, same org // .SelectMany(it => it.GroupBy(batchWrite => batchWrite.Options)) // // Create Write Point = bucket, org, ... + data // .Select(grouped => { var aggregate = grouped .Aggregate(new StringBuilder(""), (builder, batchWrite) => { var data = batchWrite.ToLineProtocol(); if (string.IsNullOrEmpty(data)) { return(builder); } if (builder.Length > 0) { builder.Append("\n"); } return(builder.Append(data)); }).Select(builder => builder.ToString()); return(aggregate.Select(records => new BatchWriteRecord(grouped.Key, records))); }) // // Jitter // .Select(source => { if (writeOptions.JitterInterval <= 0) { return(source); } return(source.Delay(_ => Observable.Timer(TimeSpan.FromMilliseconds(JitterDelay(writeOptions)), Scheduler.CurrentThread))); }) .Concat() // // Map to Async request // .Where(batchWriteItem => !string.IsNullOrEmpty(batchWriteItem.ToLineProtocol())) .Select(batchWriteItem => { var org = batchWriteItem.Options.OrganizationId; var bucket = batchWriteItem.Options.Bucket; var lineProtocol = batchWriteItem.ToLineProtocol(); var precision = batchWriteItem.Options.Precision; return(Observable .Defer(() => service.PostWriteAsyncWithIRestResponse(org, bucket, Encoding.UTF8.GetBytes(lineProtocol), null, "identity", "text/plain; charset=utf-8", null, "application/json", null, precision) .ToObservable()) .RetryWhen(f => f.SelectMany(e => { if (e is HttpException httpException) { // // This types is not able to retry // if (httpException.Status != 429 && httpException.Status != 503) { throw httpException; } var retryInterval = (httpException.RetryAfter * 1000 ?? writeOptions.RetryInterval) + JitterDelay(writeOptions); var retryable = new WriteRetriableErrorEvent(org, bucket, precision, lineProtocol, httpException, retryInterval); Publish(retryable); return Observable.Timer(TimeSpan.FromMilliseconds(retryInterval)); } throw e; })) .Select(result => { // ReSharper disable once ConvertIfStatementToReturnStatement if (result.IsSuccessful) { return Notification.CreateOnNext(result); } return Notification.CreateOnError <IRestResponse>(HttpException.Create(result)); }) .Catch <Notification <IRestResponse>, Exception>(ex => { var error = new WriteErrorEvent(org, bucket, precision, lineProtocol, ex); Publish(error); return Observable.Return(Notification.CreateOnError <IRestResponse>(ex)); }).Do(res => { if (res.Kind == NotificationKind.OnNext) { var success = new WriteSuccessEvent(org, bucket, precision, lineProtocol); Publish(success); } })); }) .Concat() .Subscribe( notification => { switch (notification.Kind) { case NotificationKind.OnNext: Trace.WriteLine($"The batch item: {notification} was processed successfully."); break; case NotificationKind.OnError: Trace.WriteLine( $"The batch item wasn't processed successfully because: {notification.Exception}"); break; default: Trace.WriteLine($"The batch item: {notification} was processed"); break; } }, exception => Trace.WriteLine($"The unhandled exception occurs: {exception}"), () => Trace.WriteLine("The WriteApi was disposed.")); }
protected internal WriteApi( InfluxDBClientOptions options, WriteService service, WriteOptions writeOptions, IDomainObjectMapper mapper, InfluxDBClient influxDbClient, IObservable <Unit> disposeCommand) { Arguments.CheckNotNull(service, nameof(service)); Arguments.CheckNotNull(writeOptions, nameof(writeOptions)); Arguments.CheckNotNull(mapper, nameof(mapper)); Arguments.CheckNotNull(influxDbClient, nameof(_influxDbClient)); Arguments.CheckNotNull(disposeCommand, nameof(disposeCommand)); _options = options; _mapper = mapper; _influxDbClient = influxDbClient; _unsubscribeDisposeCommand = disposeCommand.Subscribe(_ => Dispose()); // backpreasure - is not implemented in C# // // => use unbound buffer // // https://github.com/dotnet/reactive/issues/19 IObservable <IObservable <BatchWriteRecord> > batches = _subject // // Batching // .Publish(connectedSource => { var trigger = Observable.Merge( // triggered by time & count connectedSource.Window(TimeSpan.FromMilliseconds( writeOptions.FlushInterval), writeOptions.BatchSize, writeOptions.WriteScheduler), // flush trigger _flush ); return(connectedSource .Window(trigger)); }) // // Group by key - same bucket, same org // .SelectMany(it => it.GroupBy(batchWrite => batchWrite.Options)) // // Create Write Point = bucket, org, ... + data // .Select(grouped => { var aggregate = grouped .Aggregate(_stringBuilderPool.Get(), (builder, batchWrite) => { var data = batchWrite.ToLineProtocol(); if (string.IsNullOrEmpty(data)) { return(builder); } if (builder.Length > 0) { builder.Append("\n"); } return(builder.Append(data)); }).Select(builder => { var result = builder.ToString(); builder.Clear(); _stringBuilderPool.Return(builder); return(result); }); return(aggregate.Select(records => new BatchWriteRecord(grouped.Key, records)) .Where(batchWriteItem => !string.IsNullOrEmpty(batchWriteItem.ToLineProtocol()))); }); if (writeOptions.JitterInterval > 0) { batches = batches // // Jitter // .Select(source => { return(source.Delay(_ => Observable.Timer(TimeSpan.FromMilliseconds(RetryAttempt.JitterDelay(writeOptions)), writeOptions.WriteScheduler))); }); } var query = batches .Concat() // // Map to Async request // .Select(batchWriteItem => { var org = batchWriteItem.Options.OrganizationId; var bucket = batchWriteItem.Options.Bucket; var lineProtocol = batchWriteItem.ToLineProtocol(); var precision = batchWriteItem.Options.Precision; return(Observable .Defer(() => service.PostWriteAsyncWithIRestResponse(org, bucket, Encoding.UTF8.GetBytes(lineProtocol), null, "identity", "text/plain; charset=utf-8", null, "application/json", null, precision) .ToObservable()) .RetryWhen(f => f .Zip(Observable.Range(1, writeOptions.MaxRetries + 1), (exception, count) => new RetryAttempt(exception, count, writeOptions)) .SelectMany(attempt => { if (attempt.IsRetry()) { var retryInterval = attempt.GetRetryInterval(); var retryable = new WriteRetriableErrorEvent(org, bucket, precision, lineProtocol, attempt.Error, retryInterval); Publish(retryable); return Observable.Timer(TimeSpan.FromMilliseconds(retryInterval), writeOptions.WriteScheduler); } throw attempt.Error; })) .Select(result => { // ReSharper disable once ConvertIfStatementToReturnStatement if (result.IsSuccessful) { return Notification.CreateOnNext(result); } return Notification.CreateOnError <IRestResponse>(HttpException.Create(result, result.Content)); }) .Catch <Notification <IRestResponse>, Exception>(ex => { var error = new WriteErrorEvent(org, bucket, precision, lineProtocol, ex); Publish(error); return Observable.Return(Notification.CreateOnError <IRestResponse>(ex)); }).Do(res => { if (res.Kind == NotificationKind.OnNext) { var success = new WriteSuccessEvent(org, bucket, precision, lineProtocol); Publish(success); } })); }) .Concat() .Subscribe( notification => { switch (notification.Kind) { case NotificationKind.OnNext: Trace.WriteLine($"The batch item: {notification} was processed successfully."); break; case NotificationKind.OnError: Trace.WriteLine( $"The batch item wasn't processed successfully because: {notification.Exception}"); break; default: Trace.WriteLine($"The batch item: {notification} was processed"); break; } }, exception => { _disposed = true; Trace.WriteLine($"The unhandled exception occurs: {exception}"); }, () => { _disposed = true; Trace.WriteLine("The WriteApi was disposed."); }); }