예제 #1
0
        public void BlockUntilReady(int blockMilisecondsUntilReady)
        {
            if (!IsSdkReady())
            {
                var ready = false;
                using (var clock = new Util.SplitStopwatch())
                {
                    clock.Start();

                    while (clock.ElapsedMilliseconds <= blockMilisecondsUntilReady)
                    {
                        if (IsSdkReady())
                        {
                            ready = true;
                            break;
                        }

                        Thread.Sleep(500);
                    }

                    if (!ready)
                    {
                        throw new TimeoutException($"SDK was not ready in {blockMilisecondsUntilReady}. Could not connect to Redis");
                    }
                }
            }
        }
예제 #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);
                }
            }
        }
예제 #3
0
        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.");
        }
예제 #4
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);
            }
        }
예제 #5
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);
                }
            }
        }
예제 #6
0
        public async void SendBulkImpressionsCount(ConcurrentDictionary <KeyCache, int> impressionsCount)
        {
            using (var clock = new Util.SplitStopwatch())
            {
                clock.Start();

                var json = ConvertToJson(impressionsCount);

                var response = await ExecutePost(ImpressionsCountUrlTemplate, json);

                RecordTelemetry(nameof(SendBulkImpressionsCount), (int)response.statusCode, response.content, ResourceEnum.ImpressionCountSync, clock);
            }
        }
예제 #7
0
        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
                    });
                }
            }
        }
예제 #8
0
        public MultipleEvaluatorResult EvaluateFeatures(Key key, List <string> featureNames, Dictionary <string, object> attributes = null)
        {
            var exception             = false;
            var treatmentsForFeatures = new Dictionary <string, TreatmentResult>();

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

                try
                {
                    var splits = _splitCache.FetchMany(featureNames);

                    foreach (var feature in featureNames)
                    {
                        var split = splits.FirstOrDefault(s => feature.Equals(s?.name));

                        var result = EvaluateTreatment(key, split, feature, attributes: attributes);

                        treatmentsForFeatures.Add(feature, result);
                    }
                }
                catch (Exception e)
                {
                    _log.Error($"Exception caught getting treatments", e);

                    foreach (var name in featureNames)
                    {
                        treatmentsForFeatures.Add(name, new TreatmentResult(Labels.Exception, Control, elapsedMilliseconds: clock.ElapsedMilliseconds));
                    }

                    exception = true;
                }

                return(new MultipleEvaluatorResult
                {
                    TreatmentResults = treatmentsForFeatures,
                    ElapsedMilliseconds = clock.ElapsedMilliseconds,
                    Exception = exception
                });
            }
        }
예제 #9
0
        public TreatmentResult EvaluateFeature(Key key, string featureName, Dictionary <string, object> attributes = null)
        {
            using (var clock = new Util.SplitStopwatch())
            {
                clock.Start();

                try
                {
                    var parsedSplit = _splitCache.GetSplit(featureName);

                    return(EvaluateTreatment(key, parsedSplit, featureName, clock, attributes));
                }
                catch (Exception e)
                {
                    _log.Error($"Exception caught getting treatment for feature: {featureName}", e);

                    return(new TreatmentResult(Labels.Exception, Control, elapsedMilliseconds: clock.ElapsedMilliseconds, exception: true));
                }
            }
        }
예제 #10
0
        public async void SendBulkImpressions(List <KeyImpression> impressions)
        {
            using (var clock = new Util.SplitStopwatch())
            {
                clock.Start();

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

                    return;
                }

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

                    await BuildJsonAndPost(bulkToPost, clock);
                }
            }
        }
예제 #11
0
        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);
                }
            }
        }
예제 #12
0
        private TreatmentResult EvaluateTreatment(Key key, ParsedSplit parsedSplit, string featureName, Util.SplitStopwatch clock = null, Dictionary <string, object> attributes = null)
        {
            try
            {
                if (clock == null)
                {
                    clock = new Util.SplitStopwatch();
                    clock.Start();
                }

                if (parsedSplit == null)
                {
                    _log.Warn($"GetTreatment: you passed {featureName} that does not exist in this environment, please double check what Splits exist in the web console.");

                    return(new TreatmentResult(Labels.SplitNotFound, Control, elapsedMilliseconds: clock.ElapsedMilliseconds));
                }

                var treatmentResult = GetTreatmentResult(key, parsedSplit, attributes);

                if (parsedSplit.configurations != null && parsedSplit.configurations.ContainsKey(treatmentResult.Treatment))
                {
                    treatmentResult.Config = parsedSplit.configurations[treatmentResult.Treatment];
                }

                treatmentResult.ElapsedMilliseconds = clock.ElapsedMilliseconds;

                return(treatmentResult);
            }
            catch (Exception e)
            {
                _log.Error($"Exception caught getting treatment for feature: {featureName}", e);

                return(new TreatmentResult(Labels.Exception, Control, elapsedMilliseconds: clock.ElapsedMilliseconds));
            }
            finally
            {
                clock.Dispose();
            }
        }
예제 #13
0
        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.");
        }
예제 #14
0
        protected void RecordTelemetry(string method, int statusCode, string content, ResourceEnum resource, Util.SplitStopwatch clock)
        {
            if (statusCode >= (int)HttpStatusCode.OK && statusCode < (int)HttpStatusCode.Ambiguous)
            {
                _telemetryRuntimeProducer.RecordSyncLatency(resource, Util.Metrics.Bucket(clock.ElapsedMilliseconds));
                _telemetryRuntimeProducer.RecordSuccessfulSync(resource, CurrentTimeHelper.CurrentTimeMillis());
            }
            else
            {
                _log.Error($"Http status executing {method}: {statusCode.ToString()} - {content}");

                _telemetryRuntimeProducer.RecordSyncError(resource, statusCode);
            }
        }