public RecurringJobScheduler(
            [NotNull] JobStorage storage,
            [NotNull] IBackgroundJobClient client,
            [NotNull] IScheduleInstantFactory instantFactory,
            [NotNull] IThrottler throttler)
        {
            if (storage == null)
            {
                throw new ArgumentNullException("storage");
            }
            if (client == null)
            {
                throw new ArgumentNullException("client");
            }
            if (instantFactory == null)
            {
                throw new ArgumentNullException("instantFactory");
            }
            if (throttler == null)
            {
                throw new ArgumentNullException("throttler");
            }

            _storage        = storage;
            _client         = client;
            _instantFactory = instantFactory;
            _throttler      = throttler;
        }
Example #2
0
        /// <summary>
        /// Creates new <see cref="TogglClient"/>
        /// </summary>
        /// <param name="apiToken">Toggl API token</param>
        /// <param name="throttler">Throttler to use when invoking methods. If null, no throttling is performed</param>
        public TogglClient(string apiToken, IThrottler throttler = null)
        {
            Clients     = new ClientService(this);
            TimeEntries = new TimeEntryService(this);
            Projects    = new ProjectService(this);
            Tags        = new TagService(this);
            Tasks       = new TaskService(this);
            Users       = new UserService(this);
            Workspaces  = new WorkspaceService(this);
            Reports     = new ReportService(this);

            _jsonSerializer = JsonSerializer.CreateDefault();
            _throttler      = throttler ?? new NeutralThrottler();

            _togglHttpClient = new HttpClient();
            _togglHttpClient.DefaultRequestHeaders.Accept.Clear();
            _togglHttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            if (UserAgent != null)
            {
                _togglHttpClient.DefaultRequestHeaders.UserAgent.Add(UserAgent);
            }

            // authorization (basic)
            var authorizationParameter = Convert.ToBase64String(Encoding.GetEncoding("ascii").GetBytes($"{apiToken}:api_token"));
            var header = new AuthenticationHeaderValue("Basic", authorizationParameter);

            _togglHttpClient.DefaultRequestHeaders.Authorization = header;
        }
Example #3
0
 private async Task <IEnumerable <TApi> > getObjectsListAsync <TApi, TJson>(
     HttpClient httpClient,
     IThrottler throttler,
     UriBuilder uriBuilder)
     where TJson : TApi =>
 (IEnumerable <TApi>) await
 getSingleObjectAsync <IEnumerable <TJson>, List <TJson> >(httpClient, throttler, uriBuilder);
        private async Task <TApi> getSingleObjectAsync <TApi, TJson>(
            HttpClient httpClient,
            IThrottler throttler,
            String endpointUri)
            where TJson : TApi
        {
            Queue <Exception> exceptions = new Queue <Exception>();

            for (var attempts = 0; attempts < throttler.MaxAttempts; ++attempts)
            {
                throttler.WaitToProceed();

                try
                {
                    using (var stream = await httpClient.GetStreamAsync(endpointUri))
                        using (var reader = new JsonTextReader(new StreamReader(stream)))
                        {
                            var serializer = new JsonSerializer();
                            return(serializer.Deserialize <TJson>(reader));
                        }
                }
                catch (HttpRequestException ex)
                {
                    exceptions.Enqueue(ex);
                }
            }

            throw new AggregateException(exceptions);
        }
        private static async Task <TApi> callAndDeserializeSingleObjectAsync <TApi, TJson>(
            HttpClient httpClient,
            IThrottler throttler,
            HttpMethod method,
            Uri endpointUri,
            CancellationToken cancellationToken)
            where TJson : TApi
        {
            for (var attempts = 0; attempts < throttler.MaxRetryAttempts; ++attempts)
            {
                await throttler.WaitToProceed(cancellationToken).ConfigureAwait(false);

                using var request  = new HttpRequestMessage(method, endpointUri);
                using var response = await httpClient
                                     .SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken)
                                     .ConfigureAwait(false);

                // Check response for server and caller specified waits and retries
                if (throttler.CheckHttpResponse(response))
                {
                    return(await response.DeserializeAsync <TApi, TJson>()
                           .ConfigureAwait(false));
                }
            }

            throw new RestClientErrorException(
                      $"Unable to successfully call REST API endpoint `{endpointUri}` after {throttler.MaxRetryAttempts} attempts.");
        }
 public static Task <Boolean> DeleteAsync(
     this HttpClient httpClient,
     IThrottler throttler,
     String endpointUri,
     CancellationToken cancellationToken) =>
 callAndReturnSuccessCodeAsync(
     httpClient, throttler, HttpMethod.Delete, asUri(endpointUri), cancellationToken);
 public static Task <Boolean> DeleteAsync(
     this HttpClient httpClient,
     IThrottler throttler,
     UriBuilder uriBuilder,
     CancellationToken cancellationToken) =>
 callAndReturnSuccessCodeAsync(
     httpClient, throttler, HttpMethod.Delete, uriBuilder.Uri, cancellationToken);
Example #8
0
 private async Task <IEnumerable <TApi> > getObjectsListAsync <TApi, TJson>(
     HttpClient httpClient,
     IThrottler throttler,
     String endpointUri)
     where TJson : TApi =>
 (IEnumerable <TApi>) await
 getSingleObjectAsync <IEnumerable <TJson>, List <TJson> >(httpClient, throttler, endpointUri);
 public static Task <TApi> GetSingleObjectAsync <TApi, TJson>(
     this HttpClient httpClient,
     IThrottler throttler,
     UriBuilder uriBuilder,
     CancellationToken cancellationToken)
     where TJson : TApi =>
 callAndDeserializeSingleObjectAsync <TApi, TJson>(
     httpClient, throttler, uriBuilder.Uri, cancellationToken);
 public static Task <TApi> DeleteSingleObjectAsync <TApi, TJson>(
     this HttpClient httpClient,
     IThrottler throttler,
     String endpointUri,
     CancellationToken cancellationToken)
     where TJson : TApi =>
 callAndDeserializeSingleObjectAsync <TApi, TJson>(
     httpClient, throttler, HttpMethod.Delete, asUri(endpointUri), cancellationToken);
 private Task <TApi> getSingleObjectAsync <TApi, TJson>(
     HttpClient httpClient,
     IThrottler throttler,
     UriBuilder uriBuilder)
     where TJson : TApi
 {
     return(getSingleObjectAsync <TApi, TJson>(httpClient, throttler, uriBuilder.ToString()));
 }
Example #12
0
 public CustomJobScheduler(IServiceProvider serviceProvider,
                           IThrottler throttler,
                           Func <TaskContext, Task> func)
 {
     _serviceProvider = serviceProvider;
     _throttler       = throttler;
     _func            = func;
 }
Example #13
0
 public static Task <TApi> PatchAsync <TApi, TJson, TRequest>(
     this HttpClient httpClient,
     String endpointUri,
     TRequest request,
     IThrottler throttler,
     CancellationToken cancellationToken)
     where TJson : TApi =>
 callAndDeserializeAsync <TApi, TJson, TRequest>(
     httpClient, _httpMethodPatch, asUri(endpointUri), request, cancellationToken, throttler);
Example #14
0
 public ItemsController(
     IRepository repository,
     IGoodreads goodreads,
     IThrottler goodreadsAccess)
 {
     this.repository      = repository;
     this.goodreads       = goodreads;
     this.goodreadsAccess = goodreadsAccess;
 }
 public static async Task <IReadOnlyList <TApi> > DeleteObjectsListAsync <TApi, TJson>(
     this HttpClient httpClient,
     IThrottler throttler,
     UriBuilder uriBuilder,
     CancellationToken cancellationToken)
     where TJson : TApi =>
 (IReadOnlyList <TApi>) await callAndDeserializeSingleObjectAsync <IReadOnlyList <TJson>, List <TJson> >(
     httpClient, throttler, uriBuilder.Uri, cancellationToken, HttpMethod.Delete)
 .ConfigureAwait(false);
Example #16
0
        private async Task <TApi> callAndDeserializeSingleObjectAsync <TApi, TJson>(
            HttpClient httpClient,
            IThrottler throttler,
            Uri endpointUri,
            CancellationToken cancellationToken,
            HttpMethod method = null)
            where TJson : TApi
        {
            var exceptions = new Queue <Exception>();

            for (var attempts = 0; attempts < throttler.MaxRetryAttempts; ++attempts)
            {
                await throttler.WaitToProceed(cancellationToken).ConfigureAwait(false);

                try
                {
                    using (var request = new HttpRequestMessage(method ?? HttpMethod.Get, endpointUri))
                        using (var response = await httpClient
                                              .SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken)
                                              .ConfigureAwait(false))
                        {
                            // Check response for server and caller specified waits and retries
                            if (!throttler.CheckHttpResponse(response))
                            {
                                continue;
                            }

                            return(await deserializeAsync <TApi, TJson>(response).ConfigureAwait(false));
                        }
                }
                catch (HttpRequestException ex)
                {
                    if (attempts >= throttler.MaxRetryAttempts)
                    {
                        exceptions.Enqueue(ex);
                        break;
                    }
                    else
                    {
                        continue;
                    }
                }
                catch (Exception)
                {
                    if (attempts < throttler.MaxRetryAttempts)
                    {
                        continue;
                    }
                    else
                    {
                        throw;
                    }
                }
            }

            throw new AggregateException(exceptions);
        }
Example #17
0
 private async Task <IEnumerable <TApi> > deleteObjectsListAsync <TApi, TJson>(
     HttpClient httpClient,
     IThrottler throttler,
     UriBuilder uriBuilder,
     CancellationToken cancellationToken)
     where TJson : TApi =>
 (IEnumerable <TApi>) await callAndDeserializeSingleObjectAsync <IEnumerable <TJson>, List <TJson> >(
     httpClient, throttler, uriBuilder.Uri, cancellationToken, HttpMethod.Delete)
 .ConfigureAwait(false);
 internal RecurringDateRangeJobScheduler(
     [NotNull] IBackgroundJobFactory factory,
     [NotNull] Func <CrontabSchedule, TimeZoneInfo, IScheduleInstant> instantFactory,
     [NotNull] IThrottler throttler,
     bool ignoreTimeComponentInStartEndDates = false)
 {
     _factory        = factory ?? throw new ArgumentNullException(nameof(factory));
     _instantFactory = instantFactory ?? throw new ArgumentNullException(nameof(instantFactory));
     _throttler      = throttler ?? throw new ArgumentNullException(nameof(throttler));
     _ignoreTimeComponentInStartEndDates = ignoreTimeComponentInStartEndDates;
 }
 public FootballDataStandingProvider(IHttpClientFactory httpClientFactory,
                                     string apiToken,
                                     IMapper <StandingResponse, IEnumerable <Data.Models.Standing> > mapper,
                                     IProvider <Data.Models.Competition> competitionProvider,
                                     IThrottler throttler)
 {
     _httpClientFactory   = httpClientFactory;
     _apiToken            = apiToken;
     _mapper              = mapper;
     _competitionProvider = competitionProvider;
     _throttler           = throttler;
 }
        /// <summary>
        /// Creates new instance of <see cref="RestClient"/> object.
        /// </summary>
        /// <param name="keyId">Application key identifier.</param>
        /// <param name="secretKey">Application secret key.</param>
        /// <param name="alpacaRestApi">Alpaca REST API endpoint URL.</param>
        /// <param name="polygonRestApi">Polygon REST API endpoint URL.</param>
        /// <param name="alpacaDataApi">Alpaca REST data API endpoint URL.</param>
        /// <param name="apiVersion">Version of Alpaca api to call.  Valid values are "1" or "2".</param>
        /// <param name="dataApiVersion">Version of Alpaca data API to call.  The only valid value is currently "1".</param>
        /// <param name="isStagingEnvironment">If <c>true</c> use staging.</param>
        /// <param name="throttleParameters">Parameters for requests throttling.</param>
        public RestClient(
            String keyId,
            String secretKey,
            Uri alpacaRestApi,
            Uri polygonRestApi,
            Uri alpacaDataApi,
            Int32 apiVersion,
            Int32 dataApiVersion,
            Boolean isStagingEnvironment,
            ThrottleParameters throttleParameters)
        {
            keyId     = keyId ?? throw new ArgumentException(nameof(keyId));
            secretKey = secretKey ?? throw new ArgumentException(nameof(secretKey));

            if (!_supportedApiVersions.Contains(apiVersion))
            {
                throw new ArgumentException(nameof(apiVersion));
            }
            if (!_supportedDataApiVersions.Contains(dataApiVersion))
            {
                throw new ArgumentException(nameof(dataApiVersion));
            }

            _alpacaRestApiThrottler = throttleParameters.GetThrottler();

            _alpacaHttpClient.DefaultRequestHeaders.Add(
                "APCA-API-KEY-ID", keyId);
            _alpacaHttpClient.DefaultRequestHeaders.Add(
                "APCA-API-SECRET-KEY", secretKey);
            _alpacaHttpClient.DefaultRequestHeaders.Accept
            .Add(new MediaTypeWithQualityHeaderValue("application/json"));
            _alpacaHttpClient.BaseAddress = addApiVersionNumberSafe(
                alpacaRestApi ?? new Uri("https://api.alpaca.markets"), apiVersion);

            _alpacaDataClient.DefaultRequestHeaders.Accept
            .Add(new MediaTypeWithQualityHeaderValue("application/json"));
            _alpacaDataClient.BaseAddress = addApiVersionNumberSafe(
                alpacaDataApi ?? new Uri("https://data.alpaca.markets"), dataApiVersion);

            _polygonApiKey = keyId;
            _polygonHttpClient.DefaultRequestHeaders.Accept
            .Add(new MediaTypeWithQualityHeaderValue("application/json"));
            _polygonHttpClient.BaseAddress =
                polygonRestApi ?? new Uri("https://api.polygon.io");
            _isPolygonStaging = isStagingEnvironment ||
                                _alpacaHttpClient.BaseAddress.Host.Contains("staging");

#if NET45
            ServicePointManager.SecurityProtocol =
                SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;
#endif
        }
Example #21
0
        private async Task <TApi> getSingleObjectAsync <TApi, TJson>(
            HttpClient httpClient,
            IThrottler throttler,
            String endpointUri)
            where TJson : TApi
        {
            var exceptions = new Queue <Exception>();

            for (var attempts = 0; attempts < throttler.MaxRetryAttempts; ++attempts)
            {
                await throttler.WaitToProceed();

                try
                {
                    using (var response = await httpClient.GetAsync(endpointUri, HttpCompletionOption.ResponseHeadersRead))
                    {
                        // Check response for server and caller specified waits and retries
                        if (!throttler.CheckHttpResponse(response))
                        {
                            continue;
                        }

                        using (var stream = await response.Content.ReadAsStreamAsync())
                            using (var reader = new JsonTextReader(new StreamReader(stream)))
                            {
                                var serializer = new JsonSerializer();
                                if (response.IsSuccessStatusCode)
                                {
                                    return(serializer.Deserialize <TJson>(reader));
                                }

                                try
                                {
                                    throw new RestClientErrorException(
                                              serializer.Deserialize <JsonError>(reader));
                                }
                                catch (Exception exception)
                                {
                                    throw new RestClientErrorException(response, exception);
                                }
                            }
                    }
                }
                catch (HttpRequestException ex)
                {
                    exceptions.Enqueue(ex);
                    break;
                }
            }

            throw new AggregateException(exceptions);
        }
Example #22
0
 public CronJobScheduler(IServiceProvider serviceProvider,
                         IThrottler throttler,
                         Func <CrontabSchedule, TimeZoneInfo, IScheduleInstant> instantFactory,
                         ConcurrentDictionary <string, ProcessableCronJob> jobDictionary,
                         ILoggerFactory loggerFactory)
 {
     _serviceProvider = serviceProvider;
     _throttler       = throttler;
     _instantFactory  = instantFactory;
     _jobDictionary   = jobDictionary;
     _loggerFactory   = loggerFactory;
     _logger          = _loggerFactory.CreateLogger <CronJobScheduler>();
 }
Example #23
0
        public static async Task Task1(IThrottler throttler)
        {
            Console.WriteLine("Sync throttler...  ");
            var stopwatch = Stopwatch.StartNew();

            for (var i = 0; i < 50; i++)
            {
                // Use sync mode. Will pause when requests made in the last period have reached the limit configured
                throttler.WaitForPermission();
                await Task.Delay(100);

                Console.WriteLine($"Sync - {i}");
            }
            Console.WriteLine($"{stopwatch.Elapsed.TotalSeconds:##.00} s");
        }
        public RateLimiterBatchProcessingBehaviour(RateLimiterPolicyOptions options, SubscriberConfiguration configuration)
        {
            if (configuration.ConcurrentBatches > 1)
            {
                throw new ArgumentOutOfRangeException(nameof(configuration.ConcurrentBatches), "Rate Limiter does not support concurrent batches.");
            }

            _timer                        = options.Timer;
            _throttler                    = options.Throttler;
            _rateLimit                    = options.Configuration.RateLimit;
            _messagesProcessed            = new Deque <IntervalPerformance>(options.Configuration.RollingIntervals + 1);
            _intervalInMilliSeconds       = options.Configuration.IntervalInMilliSeconds;
            _intervalsPerMinute           = (double)1000 * 60 / options.Configuration.IntervalInMilliSeconds;
            _rollingIntervals             = options.Configuration.RollingIntervals;
            ShouldIncrementProcessingRate = options.ShouldIncrementProcessingRate;
        }
        public RecurringJobScheduler(
            [NotNull] JobStorage storage,
            [NotNull] IBackgroundJobClient client,
            [NotNull] IScheduleInstantFactory instantFactory,
            [NotNull] IThrottler throttler)
        {
            if (storage == null) throw new ArgumentNullException("storage");
            if (client == null) throw new ArgumentNullException("client");
            if (instantFactory == null) throw new ArgumentNullException("instantFactory");
            if (throttler == null) throw new ArgumentNullException("throttler");

            _storage = storage;
            _client = client;
            _instantFactory = instantFactory;
            _throttler = throttler;
        }
Example #26
0
        /// <summary>
        /// Creates new instance of <see cref="AlpacaTradingClient"/> object.
        /// </summary>
        /// <param name="configuration">Configuration parameters object.</param>
        public AlpacaTradingClient(
            AlpacaTradingClientConfiguration configuration)
        {
            configuration
            .EnsureNotNull(nameof(configuration))
            .EnsureIsValid();

            _alpacaRestApiThrottler = configuration.ThrottleParameters.GetThrottler();

            _httpClient.AddAuthenticationHeaders(configuration.SecurityId);

            _httpClient.DefaultRequestHeaders.Accept
            .Add(new MediaTypeWithQualityHeaderValue("application/json"));
            _httpClient.BaseAddress = configuration.ApiEndpoint;
            _httpClient.SetSecurityProtocol();
        }
Example #27
0
        public static async Task Task2(IThrottler throttler)
        {
            Console.WriteLine("Async throttler...");
            var stopwatch = Stopwatch.StartNew();

            for (var i = 0; i < 350; i++)
            {
                // USe async mode
                await throttler.WaitForPermissionAsync();

                Console.WriteLine($"Async - {i}");
            }

            stopwatch.Stop();

            Console.WriteLine($"{stopwatch.Elapsed.TotalSeconds:##.00} s");
        }
Example #28
0
        internal RecurringJobScheduler(
            [NotNull] IBackgroundJobFactory factory,
            [NotNull] Func <CrontabSchedule, TimeZoneInfo, IScheduleInstant> instantFactory,
            [NotNull] IThrottler throttler)
        {
            if (factory == null)
            {
                throw new ArgumentNullException(nameof(factory));
            }
            if (instantFactory == null)
            {
                throw new ArgumentNullException(nameof(instantFactory));
            }
            if (throttler == null)
            {
                throw new ArgumentNullException(nameof(throttler));
            }

            _factory        = factory;
            _instantFactory = instantFactory;
            _throttler      = throttler;
        }
 internal RecurringJobScheduler(
     [NotNull] IBackgroundJobFactory factory,
     [NotNull] Func<CrontabSchedule, TimeZoneInfo, IScheduleInstant> instantFactory,
     [NotNull] IThrottler throttler)
 {
     if (factory == null) throw new ArgumentNullException("factory");
     if (instantFactory == null) throw new ArgumentNullException("instantFactory");
     if (throttler == null) throw new ArgumentNullException("throttler");
     
     _factory = factory;
     _instantFactory = instantFactory;
     _throttler = throttler;
 }
 public ApiConnection(string productName, string productVersion)
 {
     _throttler          = new Throttler(20, TimeSpan.FromMinutes(1));
     _productInformation = new ProductHeaderValue(productName, productVersion);
 }
Example #31
0
 public static void SetupThrottler(IThrottler throttler)
 {
     _defaultThrottler = throttler;
 }
Example #32
0
 public Chunker(TableMigration migration, IDbConnection connection, MigrationOptions options)
 {
     _migration = migration;
     _connection = connection;
     _throttler = options.Throttler;
 }
Example #33
0
        /// <summary>
        /// Creates new instance of <see cref="RestClient"/> object.
        /// </summary>
        /// <param name="keyId">Application key identifier.</param>
        /// <param name="secretKey">Application secret key.</param>
        /// <param name="alpacaRestApi">Alpaca REST API endpoint URL.</param>
        /// <param name="polygonRestApi">Polygon REST API endpoint URL.</param>
        /// <param name="alpacaDataApi">Alpaca REST data API endpoint URL.</param>
        /// <param name="apiVersion">Version of Alpaca API to call.  Valid values are "1" or "2".</param>
        /// <param name="dataApiVersion">Version of Alpaca data API to call.  The only valid value is currently "1".</param>
        /// <param name="isStagingEnvironment">If <c>true</c> use staging.</param>
        /// <param name="throttleParameters">Parameters for requests throttling.</param>
        /// <param name="oauthKey">Key for alternative authentication via oauth. keyId and secretKey will be ignored if provided.</param>
        public RestClient(
            String keyId,
            String secretKey,
            Uri alpacaRestApi,
            Uri polygonRestApi,
            Uri alpacaDataApi,
            Int32 apiVersion,
            Int32 dataApiVersion,
            Boolean isStagingEnvironment,
            ThrottleParameters throttleParameters,
            String oauthKey)
        {
            keyId = keyId ?? throw new ArgumentException(
                              "Application key id should not be null", nameof(keyId));
            secretKey = secretKey ?? throw new ArgumentException(
                                  "Application secret key id should not be null", nameof(secretKey));

            if (!_supportedApiVersions.Contains(apiVersion))
            {
                throw new ArgumentException(
                          "Supported REST API versions are '1' and '2' only", nameof(apiVersion));
            }
            if (!_supportedDataApiVersions.Contains(dataApiVersion))
            {
                throw new ArgumentException(
                          "Supported Data REST API versions are '1' and '2' only", nameof(dataApiVersion));
            }

            throttleParameters      = throttleParameters ?? ThrottleParameters.Default;
            _alpacaRestApiThrottler = throttleParameters.GetThrottler();

            if (string.IsNullOrEmpty(oauthKey))
            {
                _alpacaHttpClient.DefaultRequestHeaders.Add(
                    "APCA-API-KEY-ID", keyId);
                _alpacaHttpClient.DefaultRequestHeaders.Add(
                    "APCA-API-SECRET-KEY", secretKey);
            }
            else
            {
                _alpacaHttpClient.DefaultRequestHeaders.Add(
                    "Authorization", "Bearer " + oauthKey);
            }
            _alpacaHttpClient.DefaultRequestHeaders.Accept
            .Add(new MediaTypeWithQualityHeaderValue("application/json"));
            _alpacaHttpClient.BaseAddress = addApiVersionNumberSafe(
                alpacaRestApi ?? new Uri("https://api.alpaca.markets"), apiVersion);

            _alpacaDataClient.DefaultRequestHeaders.Accept
            .Add(new MediaTypeWithQualityHeaderValue("application/json"));
            _alpacaDataClient.BaseAddress = addApiVersionNumberSafe(
                alpacaDataApi ?? new Uri("https://data.alpaca.markets"), dataApiVersion);

            _polygonApiKey = keyId;
            _polygonHttpClient.DefaultRequestHeaders.Accept
            .Add(new MediaTypeWithQualityHeaderValue("application/json"));
            _polygonHttpClient.BaseAddress =
                polygonRestApi ?? new Uri("https://api.polygon.io");
            _isPolygonStaging = isStagingEnvironment ||
                                _alpacaHttpClient.BaseAddress.Host.Contains("staging");

#if NET45
            System.Net.ServicePointManager.SecurityProtocol =
#pragma warning disable CA5364 // Do Not Use Deprecated Security Protocols
                System.Net.SecurityProtocolType.Tls12 | System.Net.SecurityProtocolType.Tls11;
#pragma warning restore CA5364 // Do Not Use Deprecated Security Protocols
#endif
        }
 public RateLimiterBuilder(ITimer timer, IThrottler throttler, SubscriberConfiguration subscriberConfiguration)
 {
     _timer     = timer;
     _throttler = throttler;
     _subscriberConfiguration = subscriberConfiguration;
 }