Ejemplo n.º 1
0
        public async Task MakeRequest(Batch batch)
        {
            Stopwatch watch = new Stopwatch();

            _backo.Reset();
            try
            {
                Uri uri = new Uri(_client.Config.Host + "/v1/import");

                // set the current request time
                batch.SentAt = DateTime.Now.ToString("o");

                string json = JsonConvert.SerializeObject(batch);

                // Basic Authentication
                // https://segment.io/docs/tracking-api/reference/#authentication
#if NET35
                _httpClient.Headers.Set("Authorization", "Basic " + BasicAuthHeader(batch.WriteKey, string.Empty));
                _httpClient.Headers.Set("Content-Type", "application/json; charset=utf-8");
#else
                _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", BasicAuthHeader(batch.WriteKey, string.Empty));
#endif
                // Prepare request data;
                var requestData = Encoding.UTF8.GetBytes(json);

                // Compress request data if compression is set
                if (_client.Config.Gzip)
                {
#if NET35
                    _httpClient.Headers.Set(HttpRequestHeader.ContentEncoding, "gzip");
#else
                    //_httpClient.DefaultRequestHeaders.Add("Content-Encoding", "gzip");
#endif

                    // Compress request data with GZip
                    using (MemoryStream memory = new MemoryStream())
                    {
                        using (GZipStream gzip = new GZipStream(memory, CompressionMode.Compress, true))
                        {
                            gzip.Write(requestData, 0, requestData.Length);
                        }
                        requestData = memory.ToArray();
                    }
                }

                Logger.Info("Sending analytics request to Segment.io ..", new Dict
                {
                    { "batch id", batch.MessageId },
                    { "json size", json.Length },
                    { "batch size", batch.batch.Count }
                });

                // Retries with exponential backoff
                int    statusCode  = (int)HttpStatusCode.OK;
                string responseStr = "";

                while (!_backo.HasReachedMax)
                {
#if NET35
                    watch.Start();

                    try
                    {
                        var response = Encoding.UTF8.GetString(_httpClient.UploadData(uri, "POST", requestData));
                        watch.Stop();

                        Succeed(batch, watch.ElapsedMilliseconds);
                        statusCode = 200;
                        break;
                    }
                    catch (WebException ex)
                    {
                        watch.Stop();

                        var response = (HttpWebResponse)ex.Response;
                        statusCode = (response != null) ? (int)response.StatusCode : 0;
                        if ((statusCode >= 500 && statusCode <= 600) || statusCode == 429 || statusCode == 0)
                        {
                            // If status code is greater than 500 and less than 600, it indicates server error
                            // Error code 429 indicates rate limited.
                            // Retry uploading in these cases.
                            Thread.Sleep(_backo.AttemptTime());
                            if (statusCode == 429)
                            {
                                Logger.Info($"Too many request at the moment CurrentAttempt:{_backo.CurrentAttempt} Retrying to send request", new Dict
                                {
                                    { "batch id", batch.MessageId },
                                    { "statusCode", statusCode },
                                    { "duration (ms)", watch.ElapsedMilliseconds }
                                });
                            }
                            else
                            {
                                Logger.Info($"Internal Segment Server error CurrentAttempt:{_backo.CurrentAttempt} Retrying to send request", new Dict
                                {
                                    { "batch id", batch.MessageId },
                                    { "statusCode", statusCode },
                                    { "duration (ms)", watch.ElapsedMilliseconds }
                                });
                            }
                            continue;
                        }
                        else
                        {
                            //If status code is greater or equal than 400 but not 429 should indicate is client error.
                            //All other types of HTTP Status code are not errors (Between 100 and 399)
                            responseStr  = String.Format("Status Code {0}. ", statusCode);
                            responseStr += ex.Message;
                            break;
                        }
                    }
#else
                    watch.Start();

                    ByteArrayContent content = new ByteArrayContent(requestData);
                    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                    if (_client.Config.Gzip)
                    {
                        content.Headers.ContentEncoding.Add("gzip");
                    }

                    HttpResponseMessage response = null;
                    bool retry = false;
                    try
                    {
                        response = await _httpClient.PostAsync(uri, content).ConfigureAwait(false);
                    }
                    catch (TaskCanceledException e)
                    {
                        Logger.Info("HTTP Post failed with exception of type TaskCanceledException", new Dict
                        {
                            { "batch id", batch.MessageId },
                            { "reason", e.Message },
                            { "duration (ms)", watch.ElapsedMilliseconds }
                        });
                        retry = true;
                    }
                    catch (OperationCanceledException e)
                    {
                        Logger.Info("HTTP Post failed with exception of type OperationCanceledException", new Dict
                        {
                            { "batch id", batch.MessageId },
                            { "reason", e.Message },
                            { "duration (ms)", watch.ElapsedMilliseconds }
                        });
                        retry = true;
                    }
                    catch (HttpRequestException e)
                    {
                        Logger.Info("HTTP Post failed with exception of type HttpRequestException", new Dict
                        {
                            { "batch id", batch.MessageId },
                            { "reason", e.Message },
                            { "duration (ms)", watch.ElapsedMilliseconds }
                        });
                        retry = true;
                    }
                    catch (System.Exception e)
                    {
                        Logger.Info("HTTP Post failed with exception of type Exception", new Dict
                        {
                            { "batch id", batch.MessageId },
                            { "reason", e.Message },
                            { "duration (ms)", watch.ElapsedMilliseconds }
                        });
                        retry = true;
                    }

                    watch.Stop();
                    statusCode = response != null ? (int)response.StatusCode : 0;

                    if (response != null && response.StatusCode == HttpStatusCode.OK)
                    {
                        Succeed(batch, watch.ElapsedMilliseconds);
                        break;
                    }
                    else
                    {
                        if ((statusCode >= 500 && statusCode <= 600) || statusCode == 429 || retry)
                        {
                            // If status code is greater than 500 and less than 600, it indicates server error
                            // Error code 429 indicates rate limited.
                            // Retry uploading in these cases.
                            await _backo.AttemptAsync();

                            if (statusCode == 429)
                            {
                                Logger.Info($"Too many request at the moment CurrentAttempt:{_backo.CurrentAttempt} Retrying to send request", new Dict
                                {
                                    { "batch id", batch.MessageId },
                                    { "statusCode", statusCode },
                                    { "duration (ms)", watch.ElapsedMilliseconds }
                                });
                            }
                            else
                            {
                                Logger.Info($"Internal Segment Server error CurrentAttempt:{_backo.CurrentAttempt} Retrying to send request", new Dict
                                {
                                    { "batch id", batch.MessageId },
                                    { "statusCode", statusCode },
                                    { "duration (ms)", watch.ElapsedMilliseconds }
                                });
                            }
                        }
                        else
                        {
                            //HTTP status codes smaller than 500 or greater than 600 except for 429 are either Client errors or a correct status
                            //This means it should not retry
                            break;
                        }
                    }
#endif
                }

                var hasBackoReachedMax = _backo.HasReachedMax;
                if (hasBackoReachedMax || statusCode != (int)HttpStatusCode.OK)
                {
                    var message = $"Has Backoff reached max: {hasBackoReachedMax} with number of Attempts:{_backo.CurrentAttempt},\n Status Code: {statusCode}\n, response message: {responseStr}";
                    Fail(batch, new APIException(statusCode.ToString(), message), watch.ElapsedMilliseconds);
                }
            }
            catch (System.Exception e)
            {
                watch.Stop();
                Fail(batch, e, watch.ElapsedMilliseconds);
            }
        }
Ejemplo n.º 2
0
        public async Task MakeRequest(Batch batch)
        {
            Stopwatch watch = new Stopwatch();

            try
            {
                Uri uri = new Uri(_client.Config.Host + "/v1/import");

                // set the current request time
                batch.SentAt = DateTime.Now.ToString("o");

                string json = JsonConvert.SerializeObject(batch);

                // Basic Authentication
                // https://segment.io/docs/tracking-api/reference/#authentication
#if NET35
                _httpClient.Headers.Set("Authorization", "Basic " + BasicAuthHeader(batch.WriteKey, string.Empty));
                _httpClient.Headers.Set("Content-Type", "application/json; charset=utf-8");
#else
                _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", BasicAuthHeader(batch.WriteKey, string.Empty));
#endif
                // Prepare request data;
                var requestData = Encoding.UTF8.GetBytes(json);

                // Compress request data if compression is set
                if (_client.Config.Gzip)
                {
#if NET35
                    _httpClient.Headers.Add(HttpRequestHeader.ContentEncoding, "gzip");
#else
                    //_httpClient.DefaultRequestHeaders.Add("Content-Encoding", "gzip");
#endif

                    // Compress request data with GZip
                    using (MemoryStream memory = new MemoryStream())
                    {
                        using (GZipStream gzip = new GZipStream(memory, CompressionMode.Compress, true))
                        {
                            gzip.Write(requestData, 0, requestData.Length);
                        }
                        requestData = memory.ToArray();
                    }
                }

                Logger.Info("Sending analytics request to Segment.io ..", new Dict
                {
                    { "batch id", batch.MessageId },
                    { "json size", json.Length },
                    { "batch size", batch.batch.Count }
                });

                // Retries with exponential backoff
                int    statusCode  = (int)HttpStatusCode.OK;
                string responseStr = "";

                while (!_backo.HasReachedMax)
                {
#if NET35
                    watch.Start();

                    try
                    {
                        var response = Encoding.UTF8.GetString(_httpClient.UploadData(uri, "POST", requestData));
                        watch.Stop();

                        Succeed(batch, watch.ElapsedMilliseconds);
                        statusCode = 200;
                        break;
                    }
                    catch (WebException ex)
                    {
                        watch.Stop();

                        var response = (HttpWebResponse)ex.Response;
                        if (response != null)
                        {
                            statusCode = (int)response.StatusCode;
                            if ((statusCode >= 500 && statusCode <= 600) || statusCode == 429)
                            {
                                // If status code is greater than 500 and less than 600, it indicates server error
                                // Error code 429 indicates rate limited.
                                // Retry uploading in these cases.
                                Thread.Sleep(_backo.AttemptTime());
                                continue;
                            }
                            else if (statusCode >= 400)
                            {
                                responseStr  = String.Format("Status Code {0}. ", statusCode);
                                responseStr += ex.Message;
                                break;
                            }
                        }
                    }
#else
                    watch.Start();

                    ByteArrayContent content = new ByteArrayContent(requestData);
                    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                    if (_client.Config.Gzip)
                    {
                        content.Headers.ContentEncoding.Add("gzip");
                    }

                    var response = await _httpClient.PostAsync(uri, content).ConfigureAwait(false);

                    watch.Stop();
                    statusCode = (int)response.StatusCode;

                    if (statusCode == (int)HttpStatusCode.OK)
                    {
                        Succeed(batch, watch.ElapsedMilliseconds);
                        break;
                    }
                    else
                    {
                        if ((statusCode >= 500 && statusCode <= 600) || statusCode == 429)
                        {
                            // If status code is greater than 500 and less than 600, it indicates server error
                            // Error code 429 indicates rate limited.
                            // Retry uploading in these cases.
                            await _backo.AttemptAsync();

                            continue;
                        }
                        else if (statusCode >= 400)
                        {
                            responseStr  = String.Format("Status Code {0}. ", response.StatusCode);
                            responseStr += await response.Content.ReadAsStringAsync().ConfigureAwait(false);

                            break;
                        }
                    }
#endif
                }

                if (_backo.HasReachedMax || statusCode != (int)HttpStatusCode.OK)
                {
                    Fail(batch, new APIException("Unexpected Status Code", responseStr), watch.ElapsedMilliseconds);
                }
            }
            catch (System.Exception e)
            {
                watch.Stop();
                Fail(batch, e, watch.ElapsedMilliseconds);
            }
        }