Exemple #1
0
        public ValidatorResult IsValid(string trafficType, string method)
        {
            if (trafficType == null)
            {
                _log.Error($"{method}: you passed a null traffic_type, traffic_type must be a non-empty string");
                return(new ValidatorResult {
                    Success = false
                });
            }

            if (trafficType == string.Empty)
            {
                _log.Error($"{method}: you passed an empty traffic_type, traffic_type must be a non-empty string");
                return(new ValidatorResult {
                    Success = false
                });
            }

            if (trafficType.Any(ch => char.IsUpper(ch)))
            {
                _log.Warn($"{method}: {trafficType} should be all lowercase - converting string to lowercase");

                trafficType = trafficType.ToLower();
            }

            if (!_splitCache.TrafficTypeExists(trafficType))
            {
                _log.Warn($"Track: Traffic Type {trafficType} does not have any corresponding Splits in this environment, make sure you’re tracking your events to a valid traffic type defined in the Split console.");
            }

            return(new ValidatorResult {
                Success = true, Value = trafficType
            });
        }
Exemple #2
0
        public async Task <string> FetchSplitChanges(long since, FetchOptions fetchOptions)
        {
            using (var clock = new Util.SplitStopwatch())
            {
                clock.Start();

                try
                {
                    var requestUri = GetRequestUri(since, fetchOptions.Till);
                    var response   = await ExecuteGet(requestUri, fetchOptions.CacheControlHeaders);

                    if ((int)response.statusCode >= (int)HttpStatusCode.OK && (int)response.statusCode < (int)HttpStatusCode.Ambiguous)
                    {
                        _telemetryRuntimeProducer.RecordSyncLatency(ResourceEnum.SplitSync, Util.Metrics.Bucket(clock.ElapsedMilliseconds));
                        _telemetryRuntimeProducer.RecordSuccessfulSync(ResourceEnum.SplitSync, CurrentTimeHelper.CurrentTimeMillis());

                        return(response.content);
                    }

                    _log.Error($"Http status executing FetchSplitChanges: {response.statusCode.ToString()} - {response.content}");

                    _telemetryRuntimeProducer.RecordSyncError(ResourceEnum.SplitSync, (int)response.statusCode);

                    return(string.Empty);
                }
                catch (Exception e)
                {
                    _log.Error("Exception caught executing FetchSplitChanges", e);

                    return(string.Empty);
                }
            }
        }
        public async void StartSse()
        {
            try
            {
                var response = await _authApiClient.AuthenticateAsync();

                _log.Debug($"Auth service response pushEnabled: {response.PushEnabled}.");

                if (response.PushEnabled.Value)
                {
                    _sseHandler.Start(response.Token, response.Channels);
                    _backOff.Reset();
                    ScheduleNextTokenRefresh(response.Expiration.Value);
                }
                else
                {
                    StopSse();
                }

                if (response.Retry.Value)
                {
                    ScheduleNextTokenRefresh(_backOff.GetInterval());
                }
            }
            catch (Exception ex)
            {
                _log.Error($"StartSse: {ex.Message}");
            }
        }
Exemple #4
0
        public async Task <bool> StartSse()
        {
            try
            {
                var response = await _authApiClient.AuthenticateAsync();

                _log.Debug($"Auth service response pushEnabled: {response.PushEnabled}.");

                if (response.PushEnabled.Value && _sseHandler.Start(response.Token, response.Channels))
                {
                    _backOff.Reset();
                    ScheduleNextTokenRefresh(response.Expiration.Value);
                    _telemetryRuntimeProducer.RecordStreamingEvent(new StreamingEvent(EventTypeEnum.TokenRefresh, CalcularteNextTokenExpiration(response.Expiration.Value)));
                    return(true);
                }

                StopSse();

                if (response.Retry.Value)
                {
                    ScheduleNextTokenRefresh(_backOff.GetInterval());
                }
                else
                {
                    ForceCancellationToken();
                }
            }
            catch (Exception ex)
            {
                _log.Error($"StartSse: {ex.Message}");
            }

            return(false);
        }
Exemple #5
0
        public virtual async Task <HTTPResult> ExecuteGet(string requestUri, bool cacheControlHeadersEnabled = false)
        {
            var result = new HTTPResult();

            var request = new HttpRequestMessage
            {
                RequestUri = new Uri(_httpClient.BaseAddress, requestUri),
                Method     = HttpMethod.Get
            };

            if (cacheControlHeadersEnabled)
            {
                request.Headers.Add(Constants.Http.CacheControlKey, Constants.Http.CacheControlValue);
            }

            try
            {
                using (var response = await _httpClient.SendAsync(request))
                {
                    result.statusCode = response.StatusCode;
                    result.content    = await response.Content.ReadAsStringAsync();
                }
            }
            catch (Exception e)
            {
                _log.Error(string.Format("Exception caught executing GET {0}", requestUri), e);
            }

            return(result);
        }
Exemple #6
0
        public ParsedSplit Parse(Split split)
        {
            try
            {
                var isValidStatus = Enum.TryParse(split.status, out StatusEnum result);

                if (!isValidStatus || result != StatusEnum.ACTIVE)
                {
                    return(null);
                }

                var parsedSplit = new ParsedSplit
                {
                    name                  = split.name,
                    killed                = split.killed,
                    defaultTreatment      = split.defaultTreatment,
                    seed                  = split.seed,
                    conditions            = new List <ConditionWithLogic>(),
                    changeNumber          = split.changeNumber,
                    trafficTypeName       = split.trafficTypeName,
                    algo                  = split.algo == 0 || split.algo == null ? AlgorithmEnum.LegacyHash : (AlgorithmEnum)split.algo,
                    trafficAllocation     = split.trafficAllocation,
                    trafficAllocationSeed = split.trafficAllocationSeed ?? 0,
                    configurations        = split.configurations
                };

                return(ParseConditions(split, parsedSplit));
            }
            catch (Exception e)
            {
                _log.Error("Exception caught parsing split", e);
                return(null);
            }
        }
Exemple #7
0
        public List <string> SplitNamesAreValid(List <string> splitNames, string method)
        {
            if (splitNames == null)
            {
                _log.Error($"{method}: split_names must be a non-empty array");
                return(splitNames);
            }

            if (!splitNames.Any())
            {
                _log.Error($"{method}: split_names must be a non-empty array");
                return(splitNames);
            }

            var dicSplits = new Dictionary <string, string>();

            foreach (var name in splitNames)
            {
                var splitNameResult = SplitNameIsValid(name, method);

                if (splitNameResult.Success)
                {
                    try { dicSplits.Add(splitNameResult.Value, splitNameResult.Value); } catch { }
                }
            }

            return(dicSplits.Keys.ToList());
        }
Exemple #8
0
        public virtual bool Track(string key, string trafficType, string eventType, double?value = null, Dictionary <string, object> properties = null)
        {
            if (_statusManager.IsDestroyed())
            {
                return(false);
            }

            using (var clock = new Util.SplitStopwatch())
            {
                clock.Start();

                var keyResult             = _keyValidator.IsValid(new Key(key, null), nameof(Track));
                var eventTypeResult       = _eventTypeValidator.IsValid(eventType, nameof(eventType));
                var eventPropertiesResult = _eventPropertiesValidator.IsValid(properties);

                var trafficTypeResult = _blockUntilReadyService.IsSdkReady()
                    ? _trafficTypeValidator.IsValid(trafficType, nameof(trafficType))
                    : new ValidatorResult {
                    Success = true, Value = trafficType
                };

                if (!keyResult || !trafficTypeResult.Success || !eventTypeResult || !eventPropertiesResult.Success)
                {
                    return(false);
                }

                try
                {
                    var eventToLog = new Event
                    {
                        key             = key,
                        trafficTypeName = trafficTypeResult.Value,
                        eventTypeId     = eventType,
                        value           = value,
                        timestamp       = CurrentTimeHelper.CurrentTimeMillis(),
                        properties      = (Dictionary <string, object>)eventPropertiesResult.Value
                    };

                    _tasksManager.Start(() =>
                    {
                        _eventsLog.Log(new WrappedEvent
                        {
                            Event = eventToLog,
                            Size  = eventPropertiesResult.EventSize
                        });
                    }, new CancellationTokenSource(), "Track");

                    RecordLatency(nameof(Track), clock.ElapsedMilliseconds);

                    return(true);
                }
                catch (Exception e)
                {
                    _log.Error("Exception caught trying to track an event", e);
                    RecordException(nameof(Track));
                    return(false);
                }
            }
        }
Exemple #9
0
        public async void SendCountMetrics(string metrics)
        {
            var response = await ExecutePost(MetricsUrlTemplate.Replace("{endpoint}", "counters"), metrics);

            if ((int)response.statusCode < (int)HttpStatusCode.OK || (int)response.statusCode >= (int)HttpStatusCode.Ambiguous)
            {
                Log.Error(string.Format("Http status executing SendCountMetrics: {0} - {1}", response.statusCode.ToString(), response.content));
            }
        }
Exemple #10
0
        public async void SendBulkImpressions(List <KeyImpression> impressions)
        {
            var impressionsJson = ConvertToJson(impressions);

            var response = await ExecutePost(TestImpressionsUrlTemplate, impressionsJson);

            if ((int)response.statusCode < (int)HttpStatusCode.OK || (int)response.statusCode >= (int)HttpStatusCode.Ambiguous)
            {
                Log.Error(string.Format("Http status executing SendBulkImpressions: {0} - {1}", response.statusCode.ToString(), response.content));
            }
        }
Exemple #11
0
        public void Validate(string apiKey)
        {
            if (apiKey == string.Empty)
            {
                _log.Error("factory instantiation: you passed and empty api_key, api_key must be a non-empty string.");
            }

            if (apiKey == null)
            {
                _log.Error("factory instantiation: you passed a null api_key, api_key must be a non-empty string.");
            }
        }
Exemple #12
0
 public void Count(string counter, long delta)
 {
     try
     {
         var task = new Task(() => worker.Count(counter, delta));
         task.Start();
     }
     catch (Exception e)
     {
         Logger.Error("Exception running count metrics task", e);
     }
 }
        private string ConvertCountMetricsToJson(Dictionary <string, Counter> countMetrics)
        {
            try
            {
                return(JsonConvert.SerializeObject(countMetrics.Select(x => new { name = x.Key, delta = x.Value.GetDelta() })));
            }
            catch (Exception e)
            {
                Logger.Error("Exception ocurred serializing count metrics", e);

                return(string.Empty);
            }
        }
        public virtual bool Track(string key, string trafficType, string eventType, double?value = null, Dictionary <string, object> properties = null)
        {
            if (Destroyed)
            {
                return(false);
            }

            var keyResult             = _keyValidator.IsValid(new Key(key, null), nameof(Track));
            var eventTypeResult       = _eventTypeValidator.IsValid(eventType, nameof(eventType));
            var eventPropertiesResult = _eventPropertiesValidator.IsValid(properties);

            var trafficTypeResult = _blockUntilReadyService.IsSdkReady()
                ? _trafficTypeValidator.IsValid(trafficType, nameof(trafficType))
                : new ValidatorResult {
                Success = true, Value = trafficType
            };

            if (!keyResult || !trafficTypeResult.Success || !eventTypeResult || !eventPropertiesResult.Success)
            {
                return(false);
            }

            try
            {
                var eventToLog = new Event
                {
                    key             = key,
                    trafficTypeName = trafficTypeResult.Value,
                    eventTypeId     = eventType,
                    value           = value,
                    timestamp       = CurrentTimeHelper.CurrentTimeMillis(),
                    properties      = (Dictionary <string, object>)eventPropertiesResult.Value
                };

                Task.Factory.StartNew(() =>
                {
                    _eventsLog.Log(new WrappedEvent
                    {
                        Event = eventToLog,
                        Size  = eventPropertiesResult.EventSize
                    });
                });

                return(true);
            }
            catch (Exception e)
            {
                _log.Error("Exception caught trying to track an event", e);
                return(false);
            }
        }
Exemple #15
0
        public async Task <string> FetchSegmentChanges(string name, long since)
        {
            var clock = new Stopwatch();

            clock.Start();

            try
            {
                var requestUri = GetRequestUri(name, since);
                var response   = await ExecuteGet(requestUri);

                if ((int)response.statusCode >= (int)HttpStatusCode.OK && (int)response.statusCode < (int)HttpStatusCode.Ambiguous)
                {
                    if (_metricsLog != null)
                    {
                        _metricsLog.Time(SegmentFetcherTime, clock.ElapsedMilliseconds);
                        _metricsLog.Count(string.Format(SegmentFetcherStatus, response.statusCode), 1);
                    }

                    if (_log.IsDebugEnabled)
                    {
                        _log.Debug($"FetchSegmentChanges with name '{name}' took {clock.ElapsedMilliseconds} milliseconds using uri '{requestUri}'");
                    }

                    return(response.content);
                }

                if (_metricsLog != null)
                {
                    _metricsLog.Count(string.Format(SegmentFetcherStatus, response.statusCode), 1);
                }

                _log.Error(response.statusCode == HttpStatusCode.Forbidden
                    ? "factory instantiation: you passed a browser type api_key, please grab an api key from the Split console that is of type sdk"
                    : string.Format("Http status executing FetchSegmentChanges: {0} - {1}", response.statusCode.ToString(), response.content));

                return(string.Empty);
            }
            catch (Exception e)
            {
                _log.Error("Exception caught executing FetchSegmentChanges", e);

                if (_metricsLog != null)
                {
                    _metricsLog.Count(SegmentFetcherException, 1);
                }

                return(string.Empty);
            }
        }
        private async Task ConnectAsync()
        {
            try
            {
                UpdateFinishedConnection(finished: false);

                _splitHttpClient = new SplitioHttpClient(new Dictionary <string, string> {
                    { "Accept", "text/event-stream" }
                });
                _cancellationTokenSource = new CancellationTokenSource();

                using (var response = await _splitHttpClient.GetAsync(_url, HttpCompletionOption.ResponseHeadersRead, _cancellationTokenSource.Token))
                {
                    _log.Debug($"Response from {_url}: {response.StatusCode}");

                    if (response.IsSuccessStatusCode)
                    {
                        try
                        {
                            using (var stream = await response.Content.ReadAsStreamAsync())
                            {
                                _log.Info($"Connected to {_url}");

                                UpdateStatus(connected: true);
                                DispatchConnected();
                                await ReadStreamAsync(stream);
                            }
                        }
                        catch (Exception ex)
                        {
                            _log.Error($"Error reading stream: {ex.Message}");
                            Disconnect(reconnect: true);
                            return;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _log.Error($"Error connecting to {_url}: {ex.Message}");
            }
            finally
            {
                UpdateFinishedConnection(finished: true);
            }

            _log.Debug("Finished Event Source client ConnectAsync.");
            Disconnect();
        }
Exemple #17
0
 public void AddToQueue(long changeNumber)
 {
     try
     {
         if (_queue != null)
         {
             _log.Debug($"Add to queue: {changeNumber}");
             _queue.TryAdd(changeNumber);
         }
     }
     catch (Exception ex)
     {
         _log.Error($"AddToQueue: {ex.Message}");
     }
 }
Exemple #18
0
        public async Task <AuthenticationResponse> AuthenticateAsync()
        {
            try
            {
                var response = await _splitioHttpClient.GetAsync(_url);

                if (response.statusCode == HttpStatusCode.OK)
                {
                    _log.Debug($"Success connection to: {_url}");

                    return(GetSuccessResponse(response.content));
                }
                else if (response.statusCode >= HttpStatusCode.BadRequest && response.statusCode < HttpStatusCode.InternalServerError)
                {
                    _log.Debug($"Problem to connect to : {_url}. Response status: {response.statusCode}");

                    return(new AuthenticationResponse {
                        PushEnabled = false, Retry = false
                    });
                }

                return(new AuthenticationResponse {
                    PushEnabled = false, Retry = true
                });
            }
            catch (Exception ex)
            {
                _log.Error(ex.Message);

                return(new AuthenticationResponse {
                    PushEnabled = false, Retry = false
                });
            }
        }
Exemple #19
0
        private async Task SendBulkEventsAsync(List <Event> events)
        {
            try
            {
                using (var clock = new Util.SplitStopwatch())
                {
                    clock.Start();

                    if (events.Count <= _maxBulkSize)
                    {
                        await BuildJsonAndPost(events, clock);

                        return;
                    }

                    while (events.Count > 0)
                    {
                        var bulkToPost = Util.Helper.TakeFromList(events, _maxBulkSize);

                        await BuildJsonAndPost(bulkToPost, clock);
                    }
                }
            }
            catch (Exception ex)
            {
                _log.Error("Exception caught sending bulk of events", ex);
            }
        }
Exemple #20
0
        private void SendBulkEvents()
        {
            if (_wrappedEventsCache.HasReachedMaxSize())
            {
                Logger.Warn("Split SDK events queue is full. Events may have been dropped. Consider increasing capacity.");
            }

            var wrappedEvents = _wrappedEventsCache.FetchAllAndClear();

            if (wrappedEvents.Count > 0)
            {
                try
                {
                    var events = wrappedEvents
                                 .Select(x => x.Event)
                                 .ToList();

                    _apiClient.SendBulkEvents(events);

                    _acumulateSize = 0;
                }
                catch (Exception e)
                {
                    Logger.Error("Exception caught updating events.", e);
                }
            }
        }
Exemple #21
0
        private void ProcessEventControl(IncomingNotification notification)
        {
            var controlEvent = (ControlNotification)notification;

            switch (controlEvent.ControlType)
            {
            case ControlType.STREAMING_PAUSED:
                DispatchOccupancyEvent(publisherAvailable: false);
                break;

            case ControlType.STREAMING_RESUMED:
                if (IsPublisherAvailable())
                {
                    DispatchOccupancyEvent(publisherAvailable: true);
                }
                break;

            case ControlType.STREAMING_DISABLED:
                DispatchPushShutdown();
                break;

            default:
                _log.Error($"Incorrect control type. {controlEvent.ControlType}");
                break;
            }
        }
Exemple #22
0
        public void Proccess(IncomingNotification notification)
        {
            try
            {
                switch (notification.Type)
                {
                case NotificationType.SPLIT_UPDATE:
                    var scn = (SplitChangeNotifiaction)notification;
                    _splitsWorker.AddToQueue(scn.ChangeNumber);
                    break;

                case NotificationType.SPLIT_KILL:
                    var skn = (SplitKillNotification)notification;
                    _splitsWorker.KillSplit(skn.ChangeNumber, skn.SplitName, skn.DefaultTreatment);
                    _splitsWorker.AddToQueue(skn.ChangeNumber);
                    break;

                case NotificationType.SEGMENT_UPDATE:
                    var sc = (SegmentChangeNotification)notification;
                    _segmentsWorker.AddToQueue(sc.ChangeNumber, sc.SegmentName);
                    break;

                default:
                    _log.Debug($"Incorrect Event type: {notification}");
                    break;
                }
            }
            catch (Exception ex)
            {
                _log.Error($"Processor: {ex.Message}");
            }
        }
Exemple #23
0
        public async Task <bool> FetchSegment(FetchOptions fetchOptions)
        {
            var success = false;

            while (true)
            {
                var changeNumber = _segmentCache.GetChangeNumber(Name);

                try
                {
                    var response = await _segmentChangeFetcher.Fetch(Name, changeNumber, fetchOptions);

                    if (response == null)
                    {
                        break;
                    }

                    if (changeNumber >= response.till)
                    {
                        success = true;
                        break;
                    }

                    if (response.added.Count() > 0 || response.removed.Count() > 0)
                    {
                        _segmentCache.AddToSegment(Name, response.added);
                        _segmentCache.RemoveFromSegment(Name, response.removed);

                        if (_log.IsDebugEnabled)
                        {
                            if (response.added.Count() > 0)
                            {
                                _log.Debug($"Segment {Name} - Added : {string.Join(" - ", response.added)}");
                            }

                            if (response.removed.Count() > 0)
                            {
                                _log.Debug($"Segment {Name} - Removed : {string.Join(" - ", response.removed)}");
                            }
                        }
                    }

                    _segmentCache.SetChangeNumber(Name, response.till);
                }
                catch (Exception e)
                {
                    _log.Error("Exception caught refreshing segment", e);
                }
                finally
                {
                    if (_log.IsDebugEnabled)
                    {
                        _log.Debug($"segment {Name} fetch before: {changeNumber}, after: {_segmentCache.GetChangeNumber(Name)}");
                    }
                }
            }

            return(success);
        }
Exemple #24
0
 public void AddToQueue(long changeNumber, string segmentName)
 {
     try
     {
         if (_queue != null)
         {
             _log.Debug($"Add to queue: {segmentName} - {changeNumber}");
             _queue.TryAdd(new SegmentQueueDto {
                 ChangeNumber = changeNumber, SegmentName = segmentName
             });
         }
     }
     catch (Exception ex)
     {
         _log.Error($"AddToQueue: {ex.Message}");
     }
 }
Exemple #25
0
        public void HandleIncomingEvent(IncomingNotification notification)
        {
            switch (notification.Type)
            {
            case NotificationType.CONTROL:
                ProcessEventControl(notification);
                break;

            case NotificationType.OCCUPANCY:
                ProcessEventOccupancy(notification);
                break;

            default:
                _log.Error($"Incorrect notification type: {notification.Type}");
                break;
            }
        }
Exemple #26
0
        private void RecordInit()
        {
            try
            {
                var config = new Config
                {
                    BURTimeouts     = _telemetryStorageConsumer.GetBURTimeouts(),
                    EventsQueueSize = _configurationOptions.EventLogSize,
                    Rates           = new Rates
                    {
                        Events      = _configurationOptions.EventLogRefreshRate,
                        Impressions = _configurationOptions.TreatmentLogRefreshRate,
                        Segments    = _configurationOptions.SegmentRefreshRate,
                        Splits      = _configurationOptions.SplitsRefreshRate,
                        Telemetry   = _configurationOptions.TelemetryRefreshRate
                    },
                    UrlOverrides = new UrlOverrides
                    {
                        Sdk       = !_configurationOptions.BaseUrl.Equals(Constants.Urls.BaseUrl),
                        Events    = !_configurationOptions.EventsBaseUrl.Equals(Constants.Urls.EventsBaseUrl),
                        Auth      = !_configurationOptions.AuthServiceURL.Equals(Constants.Urls.AuthServiceURL),
                        Stream    = !_configurationOptions.StreamingServiceURL.Equals(Constants.Urls.StreamingServiceURL),
                        Telemetry = !_configurationOptions.TelemetryServiceURL.Equals(Constants.Urls.TelemetryServiceURL)
                    },
                    StreamingEnabled          = _configurationOptions.StreamingEnabled,
                    ImpressionsMode           = _configurationOptions.ImpressionsMode,
                    ImpressionListenerEnabled = _configurationOptions.ImpressionListener != null,
                    OperationMode             = (int)_configurationOptions.Mode,
                    ImpressionsQueueSize      = _configurationOptions.TreatmentLogSize,
                    Tags = _telemetryStorageConsumer.PopTags().ToList(),
                    TimeUntilSDKReady        = CurrentTimeHelper.CurrentTimeMillis() - _configurationOptions.SdkStartTime,
                    ActiveFactories          = _factoryInstantiationsService.GetActiveFactories(),
                    RedundantActiveFactories = _factoryInstantiationsService.GetRedundantActiveFactories(),
                    Storage           = Constants.StorageType.Memory,
                    SDKNotReadyUsage  = _telemetryStorageConsumer.GetNonReadyUsages(),
                    HTTPProxyDetected = IsHTTPProxyDetected()
                };

                _telemetryAPI.RecordConfigInit(config);
            }
            catch (Exception ex)
            {
                _log.Error("Something were wrong posting Config.", ex);
            }
        }
Exemple #27
0
        public async Task <string> FetchSplitChanges(long since)
        {
            var clock = new Stopwatch();

            clock.Start();

            try
            {
                var requestUri = GetRequestUri(since);
                var response   = await ExecuteGet(requestUri);

                if ((int)response.statusCode >= (int)HttpStatusCode.OK && (int)response.statusCode < (int)HttpStatusCode.Ambiguous)
                {
                    if (_metricsLog != null)
                    {
                        _metricsLog.Time(SplitFetcherTime, clock.ElapsedMilliseconds);
                        _metricsLog.Count(string.Format(SplitFetcherStatus, response.statusCode), 1);
                    }

                    return(response.content);
                }
                else
                {
                    _log.Error(string.Format("Http status executing FetchSplitChanges: {0} - {1}", response.statusCode.ToString(), response.content));

                    if (_metricsLog != null)
                    {
                        _metricsLog.Count(string.Format(SplitFetcherStatus, response.statusCode), 1);
                    }

                    return(string.Empty);
                }
            }
            catch (Exception e)
            {
                _log.Error("Exception caught executing FetchSplitChanges", e);

                if (_metricsLog != null)
                {
                    _metricsLog.Count(SplitFetcherException, 1);
                }

                return(string.Empty);
            }
        }
        public void SetChangeNumber(long changeNumber)
        {
            if (changeNumber < _changeNumber)
            {
                Log.Error("ChangeNumber for splits cache is less than previous");
            }

            _changeNumber = changeNumber;
        }
        public void AddToQueue(long changeNumber)
        {
            try
            {
                if (!_running)
                {
                    _log.Debug("Splits Worker not running.");
                    return;
                }

                _log.Debug($"Add to queue: {changeNumber}");
                _queue.TryAdd(changeNumber);
            }
            catch (Exception ex)
            {
                _log.Error($"AddToQueue: {ex.Message}");
            }
        }
        public async void RefreshSegment()
        {
            while (true)
            {
                var changeNumber = segmentCache.GetChangeNumber(name);

                try
                {
                    var response = await segmentChangeFetcher.Fetch(name, changeNumber);

                    if (response == null)
                    {
                        break;
                    }
                    if (changeNumber >= response.till)
                    {
                        gates.SegmentIsReady(name);
                        break;
                    }

                    if (response.added.Count() > 0 || response.removed.Count() > 0)
                    {
                        segmentCache.AddToSegment(name, response.added);
                        segmentCache.RemoveFromSegment(name, response.removed);

                        if (response.added.Count() > 0)
                        {
                            if (Log.IsDebugEnabled)
                            {
                                Log.Debug(string.Format("Segment {0} - Added : {1}", name, string.Join(" - ", response.added)));
                            }
                        }
                        if (response.removed.Count() > 0)
                        {
                            if (Log.IsDebugEnabled)
                            {
                                Log.Debug(string.Format("Segment {0} - Removed : {1}", name, string.Join(" - ", response.removed)));
                            }
                        }
                    }

                    segmentCache.SetChangeNumber(name, response.till);
                }
                catch (Exception e)
                {
                    Log.Error("Exception caught refreshing segment", e);
                }
                finally
                {
                    if (Log.IsDebugEnabled)
                    {
                        Log.Debug(string.Format("segment {0} fetch before: {1}, after: {2}", name, changeNumber, segmentCache.GetChangeNumber(name)));
                    }
                }
            }
        }