private async Task BuildJsonAndPost(List <Event> events, Util.SplitStopwatch clock) { var eventsJson = JsonConvert.SerializeObject(events, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); for (int i = 0; i < MaxAttempts; i++) { if (i > 0) { _wrapperAdapter.TaskDelay(500).Wait(); } var response = await ExecutePost(EventsUrlTemplate, eventsJson); RecordTelemetry(nameof(SendBulkEventsTask), (int)response.statusCode, response.content, ResourceEnum.EventSync, clock); if (response.statusCode >= System.Net.HttpStatusCode.OK && response.statusCode < System.Net.HttpStatusCode.Ambiguous) { _log.Debug($"Post bulk events success in {i} attempts."); return; } } _log.Debug($"Post bulk events fail after {MaxAttempts} attempts."); }
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 }); } }
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); }
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}"); } }
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); }
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))); } } } }
public async Task <FetchResult> FetchSplits(FetchOptions fetchOptions) { var segmentNames = new List <string>(); var names = new Dictionary <string, string>(); var success = false; while (true) { var changeNumber = _splitCache.GetChangeNumber(); try { var result = await _splitChangeFetcher.Fetch(changeNumber, fetchOptions); if (result == null) { break; } if (changeNumber >= result.till) { success = true; //There are no new split changes break; } if (result.splits != null && result.splits.Count > 0) { segmentNames.AddRange(UpdateSplitsFromChangeFetcherResponse(result.splits)); _splitCache.SetChangeNumber(result.till); } } catch (Exception e) { _log.Error("Exception caught refreshing splits", e); Stop(); } finally { if (_log.IsDebugEnabled) { _log.Debug($"split fetch before: {changeNumber}, after: {_splitCache.GetChangeNumber()}"); } } } return(new FetchResult { Success = success, SegmentNames = segmentNames }); }
private void UpdateSplitsFromChangeFetcherResponse(List <Split> splitChanges) { var addedSplits = new List <Split>(); var removedSplits = new List <Split>(); foreach (Split split in splitChanges) { //If not active --> Remove Split var isValidStatus = Enum.TryParse(split.status, out StatusEnum result); if (!isValidStatus || result != StatusEnum.ACTIVE) { _splitCache.RemoveSplit(split.name); removedSplits.Add(split); } else { var isUpdated = _splitCache.AddOrUpdate(split.name, _splitParser.Parse(split)); if (!isUpdated) { //If not existing in _splits, its a new split addedSplits.Add(split); } } } if (addedSplits.Count() > 0) { var addedFeatureNames = addedSplits .Select(x => x.name) .ToList(); if (_log.IsDebugEnabled) { _log.Debug(string.Format("Added features: {0}", string.Join(" - ", addedFeatureNames))); } } if (removedSplits.Count() > 0) { var removedFeatureNames = removedSplits .Select(x => x.name) .ToList(); if (_log.IsDebugEnabled) { _log.Debug(string.Format("Deleted features: {0}", string.Join(" - ", removedFeatureNames))); } } }
public void Start(string token, string channels) { try { _log.Debug($"SSE Handler starting..."); var url = $"{_streaminServiceUrl}?channels={channels}&v=1.1&accessToken={token}"; _eventSourceClient.ConnectAsync(url); } catch (Exception ex) { _log.Error($"SSE Handler Start: {ex.Message}"); } }
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}"); } }
public void SplitsAreReady() { if (!splitsAreReady.IsSet) { splitsAreReady.Signal(); if (splitsAreReady.IsSet) { _splitsReadyTimer.Stop(); if (Log.IsDebugEnabled) { Log.Debug($"Splits are ready in {_splitsReadyTimer.ElapsedMilliseconds} milliseconds"); } } } }
public void ExecuteTasks(CancellationToken token) { while (true) { if (counter < numberOfParallelTasks) { SelfRefreshingSegment segment; //Wait indefinitely until a segment is queued if (SegmentTaskQueue.segmentsQueue.TryTake(out segment, -1)) { if (Log.IsDebugEnabled) { Log.Debug(string.Format("Segment dequeued: {0}", segment.name)); } IncrementCounter(); Task task = new Task(() => segment.RefreshSegment(), token); task.ContinueWith((x) => { DecrementCounter(); }); task.Start(); } } else { waitForExecution.WaitOne(); } } }
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}"); } }
/// <summary> /// Mains the periodic task action. /// </summary> private static void MainPeriodicTaskAction(int intervalInMilliseconds, CancellationToken cancelToken, Action wrapperAction) { // using a ManualResetEventSlim as it is more efficient in small intervals. // In the case where longer intervals are used, it will automatically use // a standard WaitHandle.... // see http://msdn.microsoft.com/en-us/library/vstudio/5hbefs30(v=vs.100).aspx using (ManualResetEventSlim periodResetEvent = new ManualResetEventSlim(false)) { while (true) { if (cancelToken.IsCancellationRequested) { break; } Task subTask = Task.Factory.StartNew(wrapperAction, cancelToken); try { periodResetEvent.Wait(intervalInMilliseconds, cancelToken); } catch (Exception ex) { _log.Debug(ex.Message); } finally { periodResetEvent.Reset(); } } } }
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}"); } }
public void StartPeriodicDataRecording() { _impressionsLog.Start(); _eventsLog.Start(); _metricsLog.Start(); _log.Debug("Periodic Data Recording started..."); }
public override void InitializeSegment(string name) { _segments.TryGetValue(name, out SelfRefreshingSegment segment); if (segment == null) { segment = new SelfRefreshingSegment(name, _segmentChangeFetcher, _gates, _segmentCache); _segments.TryAdd(name, segment); SegmentTaskQueue.segmentsQueue.TryAdd(segment); if (_log.IsDebugEnabled) { _log.Debug($"Segment queued: {segment.name}"); } } }
public async Task <AuthenticationResponse> AuthenticateAsync() { using (var clock = new Util.SplitStopwatch()) { clock.Start(); try { var response = await _splitioHttpClient.GetAsync(_url); if (response.statusCode == HttpStatusCode.OK) { _log.Debug($"Success connection to: {_url}"); _telemetryRuntimeProducer.RecordSyncLatency(ResourceEnum.TokenSync, Util.Metrics.Bucket(clock.ElapsedMilliseconds)); _telemetryRuntimeProducer.RecordSuccessfulSync(ResourceEnum.TokenSync, CurrentTimeHelper.CurrentTimeMillis()); 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}"); _telemetryRuntimeProducer.RecordAuthRejections(); return(new AuthenticationResponse { PushEnabled = false, Retry = false }); } _telemetryRuntimeProducer.RecordSyncError(ResourceEnum.TokenSync, (int)response.statusCode); return(new AuthenticationResponse { PushEnabled = false, Retry = true }); } catch (Exception ex) { _log.Error(ex.Message); return(new AuthenticationResponse { PushEnabled = false, Retry = false }); } } }
public async Task FetchSplits() { while (true) { var changeNumber = _splitCache.GetChangeNumber(); try { var result = await _splitChangeFetcher.Fetch(changeNumber); if (result == null) { break; } if (changeNumber >= result.till) { _gates.SplitsAreReady(); //There are no new split changes break; } if (result.splits != null && result.splits.Count > 0) { UpdateSplitsFromChangeFetcherResponse(result.splits); _splitCache.SetChangeNumber(result.till); } } catch (Exception e) { _log.Error("Exception caught refreshing splits", e); Stop(); } finally { if (_log.IsDebugEnabled) { _log.Debug(string.Format("split fetch before: {0}, after: {1}", changeNumber, _splitCache.GetChangeNumber())); } } } }
public void AddToQueue(long changeNumber, string segmentName) { try { if (!_running) { _log.Error("Segments Worker not running."); return; } _log.Debug($"Add to queue: {segmentName} - {changeNumber}"); _queue.TryAdd(new SegmentQueueDto { ChangeNumber = changeNumber, SegmentName = segmentName }); } catch (Exception ex) { _log.Error($"AddToQueue: {ex.Message}"); } }
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}"); } }
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(); }
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); } }
public void ExecuteTasks(CancellationToken token) { while (!token.IsCancellationRequested) { if (_counter < _numberOfParallelTasks) { try { //Wait indefinitely until a segment is queued if (_segmentTaskQueue.GetQueue().TryTake(out SelfRefreshingSegment segment, -1, token)) { if (Log.IsDebugEnabled) { Log.Debug(string.Format("Segment dequeued: {0}", segment.Name)); } if (!token.IsCancellationRequested) { IncrementCounter(); Task task = new Task(async() => await segment.FetchSegment(new FetchOptions()), token); task.ContinueWith((x) => { DecrementCounter(); }, token); task.Start(); } } } catch (Exception ex) { Log.Debug(ex.Message); } } else { waitForExecution.WaitOne(); } } }
private async Task BuildJsonAndPost(List <KeyImpression> impressions, Util.SplitStopwatch clock) { var impressionsJson = ConvertToJson(impressions); for (int i = 0; i < MaxAttempts; i++) { if (i > 0) { _wrapperAdapter.TaskDelay(500).Wait(); } var response = await ExecutePost(TestImpressionsUrlTemplate, impressionsJson); RecordTelemetry(nameof(SendBulkImpressions), (int)response.statusCode, response.content, ResourceEnum.ImpressionSync, clock); if (response.statusCode >= System.Net.HttpStatusCode.OK && response.statusCode < System.Net.HttpStatusCode.Ambiguous) { _log.Debug($"Post bulk impressions success in {i} attempts."); return; } } _log.Debug($"Post bulk impressions fail after {MaxAttempts} attempts."); }
private async Task ExecutePost(string url, object data, string method) { var jsonData = JsonConvert.SerializeObject(data, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); var response = await _splitioHttpClient.PostAsync($"{_telemetryURL}{url}", jsonData); if ((int)response.statusCode >= (int)HttpStatusCode.OK && (int)response.statusCode < (int)HttpStatusCode.Ambiguous) { _telemetryRuntimeProducer.RecordSuccessfulSync(ResourceEnum.TelemetrySync, CurrentTimeHelper.CurrentTimeMillis()); _log.Debug($"Telemetry post success. {method}"); } else { _log.Error($"Http status executing {method}: {response.statusCode} - {response.content}"); _telemetryRuntimeProducer.RecordSyncError(ResourceEnum.TelemetrySync, (int)response.statusCode); } }
public async Task <string> FetchSegmentChanges(string name, long since, FetchOptions fetchOptions) { using (var clock = new Util.SplitStopwatch()) { clock.Start(); try { var requestUri = GetRequestUri(name, since, fetchOptions.Till); var response = await ExecuteGet(requestUri, fetchOptions.CacheControlHeaders); if ((int)response.statusCode >= (int)HttpStatusCode.OK && (int)response.statusCode < (int)HttpStatusCode.Ambiguous) { if (_log.IsDebugEnabled) { _log.Debug($"FetchSegmentChanges with name '{name}' took {clock.ElapsedMilliseconds} milliseconds using uri '{requestUri}'"); } _telemetryRuntimeProducer.RecordSyncLatency(ResourceEnum.SegmentSync, Util.Metrics.Bucket(clock.ElapsedMilliseconds)); _telemetryRuntimeProducer.RecordSuccessfulSync(ResourceEnum.SegmentSync, CurrentTimeHelper.CurrentTimeMillis()); return(response.content); } _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" : $"Http status executing FetchSegmentChanges: {response.statusCode.ToString()} - {response.content}"); _telemetryRuntimeProducer.RecordSyncError(ResourceEnum.SegmentSync, (int)response.statusCode); return(string.Empty); } catch (Exception e) { _log.Error("Exception caught executing FetchSegmentChanges", e); return(string.Empty); } } }
private async Task ConnectAsync() { try { _wrapperAdapter.TaskDelay(Convert.ToInt32(_backOff.GetInterval()) * 1000).Wait(); _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)) { UpdateFinishedConnection(finished: false); try { using (var stream = await response.Content.ReadAsStreamAsync()) { _log.Info($"Connected to {_url}"); UpdateStatus(connected: true); _backOff.Reset(); DispatchConnected(); await ReadStreamAsync(stream); } } catch (Exception ex) { _log.Error($"Error reading stream: {ex.Message}"); ReconnectAsync(); } } } catch (Exception ex) { _log.Error($"Error connecting to {_url}: {ex.Message}"); } _log.Debug("Finished Event Source client ConnectAsync."); Disconnect(); UpdateFinishedConnection(finished: true); }
public void TaskWaitAndDispose(params Task[] tasks) { #if !NETSTANDARD1_6 try { foreach (var t in tasks) { if (t == null || t.Status == TaskStatus.Canceled) { continue; } t.Wait(); t.Dispose(); } } catch (Exception ex) { _log.Debug(ex.Message); } #endif }
public void Start() { _tasksManager.Start(() => { try { while (!_synchronizer.SyncAll(_shutdownCancellationTokenSource, asynchronous: false)) { _wrapperAdapter.TaskDelay(500).Wait(); } _statusManager.SetReady(); _telemetrySyncTask.RecordConfigInit(); _synchronizer.StartPeriodicDataRecording(); if (_streamingEnabled) { _log.Debug("Starting streaming mode..."); var connected = _pushManager.StartSse().Result; if (connected) { return; } } _log.Debug("Starting polling mode ..."); _synchronizer.StartPeriodicFetching(); _telemetryRuntimeProducer.RecordStreamingEvent(new StreamingEvent(EventTypeEnum.SyncMode, (int)SyncModeEnum.Polling)); } catch (Exception ex) { _log.Debug("Exception initialization SDK.", ex); } }, _shutdownCancellationTokenSource, "SDK Initialization"); }