Ejemplo n.º 1
0
        private async Task LoadVersionLoop()
        {
            while (ShutdownToken.IsCancellationRequested == false)
            {
                ConsulResponse response = null;
                var            config   = GetConfig();

                if (config.UseLongPolling)
                {
                    response = await LoadServiceVersion().ConfigureAwait(false);
                }
                else
                {
                    await _waitForConfigChange.Task.ConfigureAwait(false);

                    continue;
                }

                var delay = TimeSpan.FromMilliseconds(0);

                if (response.Success)
                {
                    _initializedVersion.TrySetResult(true);
                }
                else if (response.IsDeploymentDefined == false)
                {
                    delay = config.ServiceMissingRetryInterval;
                }
                else
                {
                    delay = config.ErrorRetryInterval;
                }

                await _dateTime.Delay(delay).ConfigureAwait(false);
            }
        }
Ejemplo n.º 2
0
        private async Task UpdateAndMonitorAvailabilityZoneAsync()
        {
            void SetInfoStatus(AvailabilityZoneInfo.StatusCodes statusCode, string errorMessage, string consulZoneSettingsKey, Exception innerException)
            {
                var tags = GetUnencryptedTags(new Dictionary <string, string> {
                    { "ConsulZoneSettingsKey", consulZoneSettingsKey }
                });

                Info.StatusCode = statusCode;
                Info.Exception  = new EnvironmentException(errorMessage, innerException, unencrypted: tags);
            }

            const string folder      = "ZoneSettings";
            ulong        modifyIndex = 0;

            SetInfoStatus(AvailabilityZoneInfo.StatusCodes.InitializingConnectionToConsul,
                          "Initialize connection to consul",
                          $"{folder}/{Info.ServiceName}", null);

            while (_disposeCancellationToken.IsCancellationRequested == false)
            {
                try
                {
                    ConsulResponse <DbKeyValue> response = null;
                    bool exceptionThrown = false;
                    try
                    {
                        response = await _consulClient.GetKey <DbKeyValue>(modifyIndex, folder, Info.ServiceName, _disposeCancellationToken);
                    }
                    catch (Exception e)
                    {
                        SetInfoStatus(AvailabilityZoneInfo.StatusCodes.FailedOrInvalidKeyFromConsul,
                                      "Failed to get key or Invalid key",
                                      $"{folder}/{Info.ServiceName}", e);
                        exceptionThrown = true;
                    }

                    if (exceptionThrown)
                    {
                        await Task.Delay(TimeSpan.FromSeconds(1), _disposeCancellationToken);

                        continue;
                    }

                    if (response == null)
                    {
                        SetInfoStatus(AvailabilityZoneInfo.StatusCodes.FailedConnectToConsul,
                                      $"Failed to connect to consul. Service Unavailable{Environment.NewLine}Keeping activity on previous valid deployment identifier cluster",
                                      $"{folder}/{Info.ServiceName}", null);
                    }
                    else if (response.StatusCode == null ||
                             response.StatusCode >= HttpStatusCode.InternalServerError ||
                             response.StatusCode < HttpStatusCode.OK)
                    {
                        if (response.StatusCode == HttpStatusCode.Continue)
                        {
                            // TODO: handle continue
                        }

                        SetInfoStatus(AvailabilityZoneInfo.StatusCodes.ConsulInternalError,
                                      $"Consul internal error. Service returned error status: '{(response.StatusCode?.ToString() ?? "NULL")}', error: '{response.ResponseContent}'{Environment.NewLine}Keeping activity on previous valid cluster",
                                      $"{folder}/{Info.ServiceName}", null);
                    }
                    else if (response.Error != null)
                    {
                        SetInfoStatus(AvailabilityZoneInfo.StatusCodes.MissingOrInvalidKeyValue,
                                      $"Missing or invalid key in consul. Error: {response.Error.Message}",
                                      $"{folder}/{Info.ServiceName}", response.Error);
                    }
                    else
                    {
                        modifyIndex = response.ModifyIndex ?? 0;
                        await SetDeploymentIdentifierAsync(response.ResponseObject, _disposeCancellationToken);

                        if (Info.StatusCode == AvailabilityZoneInfo.StatusCodes.Ok)
                        {
                            _initialReadZonesTask.TrySetResult(default);
Ejemplo n.º 3
0
        private async Task <ConsulResponse <TResponseData> > MakeRequestAsync <TResponseData>(ConsulRequest request, string resourcePath, HttpMethod httpMethod, object requestData = null, IDictionary <string, string> headers = null, bool rawRequest = false, bool rawResponse = false, Func <HttpResponseMessage, bool> postResponseFunc = null) where TResponseData : class
        {
            try
            {
                if (request != null)
                {
                    if (request.Index != null)
                    {
                        var kv     = "index=" + request.Index.Value;
                        var joiner = resourcePath.Contains("?") ? "&" : "?";

                        resourcePath = resourcePath + joiner + kv;
                    }

                    if (!string.IsNullOrWhiteSpace(request.Wait))
                    {
                        var kv     = "wait=" + request.Wait;
                        var joiner = resourcePath.Contains("?") ? "&" : "?";

                        resourcePath = resourcePath + joiner + kv;
                    }

                    if (request.ConsistencyMode != ConsistencyMode.@default)
                    {
                        var joiner = resourcePath.Contains("?") ? "&" : "?";
                        resourcePath = resourcePath + joiner + request.ConsistencyMode.ToString();
                    }

                    if (!string.IsNullOrWhiteSpace(request.ContentHash))
                    {
                        var kv     = "hash=" + request.ContentHash;
                        var joiner = resourcePath.Contains("?") ? "&" : "?";

                        resourcePath = resourcePath + joiner + kv;
                    }

                    if (!string.IsNullOrWhiteSpace(request.FilterExpression))
                    {
                        var kv     = "filter=" + request.FilterExpression;
                        var joiner = resourcePath.Contains("?") ? "&" : "?";

                        resourcePath = resourcePath + joiner + kv;
                    }

                    if (request.Cached == true)
                    {
                        var joiner = resourcePath.Contains("?") ? "&" : "?";
                        resourcePath = resourcePath + joiner + "cached";
                    }

                    if (request.PrettyJsonResponse == true)
                    {
                        var joiner = resourcePath.Contains("?") ? "&" : "?";
                        resourcePath = resourcePath + joiner + "pretty";
                    }
                }

                byte[] dummyByteArray = new byte[1];

                var requestUri = new Uri(_httpClient.BaseAddress, resourcePath);

                HttpContent requestContent = null;

                if (requestData != null)
                {
                    if (dummyByteArray.GetType() == requestData.GetType())
                    {
                        requestContent = new ByteArrayContent(requestData as byte[]);
                    }
                    else
                    {
                        requestContent = new StringContent((rawRequest ? requestData.ToString() : JsonConvert.SerializeObject(requestData)), Encoding.UTF8);
                    }
                }

                HttpRequestMessage httpRequestMessage = null;

                switch (httpMethod.ToString().ToUpperInvariant())
                {
                case "GET":

                    httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri);
                    break;

                case "DELETE":

                    httpRequestMessage = new HttpRequestMessage(HttpMethod.Delete, requestUri);
                    break;

                case "POST":

                    httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri)
                    {
                        Content = requestContent
                    };

                    break;

                case "PUT":

                    httpRequestMessage = new HttpRequestMessage(HttpMethod.Put, requestUri)
                    {
                        Content = requestContent
                    };

                    break;

                case "HEAD":

                    httpRequestMessage = new HttpRequestMessage(HttpMethod.Head, requestUri);
                    break;

                default:
                    throw new NotSupportedException("The Http Method is not supported: " + httpMethod);
                }

                if (headers != null)
                {
                    foreach (var kv in headers)
                    {
                        httpRequestMessage.Headers.Remove(kv.Key);
                        httpRequestMessage.Headers.Add(kv.Key, kv.Value);
                    }
                }

                ConsulClientSettings.BeforeApiRequestAction?.Invoke(_httpClient, httpRequestMessage);

                var httpResponseMessage = await _httpClient.SendAsync(httpRequestMessage).ConfigureAwait(ConsulClientSettings.ContinueAsyncTasksOnCapturedContext);

                var response = new ConsulResponse <TResponseData>();

                IEnumerable <string> values;

                if (httpResponseMessage.Headers.TryGetValues(ConsulIndexHeaderKey, out values) && values != null)
                {
                    // for cross platform, use the iterator instead of linq stuff.
                    foreach (var value in values)
                    {
                        response.Index = ulong.Parse(value);
                        break;
                    }
                }

                values = null;

                if (httpResponseMessage.Headers.TryGetValues(ConsulLastContactHeaderKey, out values) && values != null)
                {
                    foreach (var value in values)
                    {
                        response.LastContactMilliseconds = ulong.Parse(value);
                        break;
                    }
                }

                values = null;

                if (httpResponseMessage.Headers.TryGetValues(ConsulKnownLeaderHeaderKey, out values) && values != null)
                {
                    foreach (var value in values)
                    {
                        response.KnownLeader = bool.Parse(value);
                        break;
                    }
                }

                values = null;

                if (httpResponseMessage.Headers.TryGetValues(ConsulContentHashHeaderKey, out values) && values != null)
                {
                    foreach (var value in values)
                    {
                        response.ContentHash = value;
                        break;
                    }
                }

                values = null;

                if (httpResponseMessage.Headers.TryGetValues(CacheHeaderKey, out values) && values != null)
                {
                    foreach (var value in values)
                    {
                        response.CacheAction = value;
                        break;
                    }
                }

                values = null;

                if (httpResponseMessage.Headers.TryGetValues(AgeHeaderKey, out values) && values != null)
                {
                    foreach (var value in values)
                    {
                        if (int.TryParse(value, out var intValue))
                        {
                            response.CacheHitAgeSeconds = intValue;
                            break;
                        }
                    }
                }

                ConsulClientSettings.AfterApiResponseAction?.Invoke(httpResponseMessage);

                if (httpResponseMessage.IsSuccessStatusCode || (postResponseFunc?.Invoke(httpResponseMessage) == true))
                {
                    if (rawResponse)
                    {
                        if (typeof(TResponseData) == dummyByteArray.GetType())
                        {
                            dummyByteArray = await httpResponseMessage.Content.ReadAsByteArrayAsync().ConfigureAwait(ConsulClientSettings.ContinueAsyncTasksOnCapturedContext);

                            response.Data = dummyByteArray as TResponseData;
                        }
                        else
                        {
                            var responseText = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(ConsulClientSettings.ContinueAsyncTasksOnCapturedContext);

                            if (!string.IsNullOrWhiteSpace(responseText))
                            {
                                response.Data = responseText as TResponseData;
                            }
                        }
                    }
                    else
                    {
                        var responseText = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(ConsulClientSettings.ContinueAsyncTasksOnCapturedContext);

                        if (!string.IsNullOrWhiteSpace(responseText))
                        {
                            response.Data = JsonConvert.DeserializeObject <TResponseData>(responseText);
                        }
                    }

                    return(response);
                }

                throw new ConsulApiException(httpResponseMessage.StatusCode, await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(ConsulClientSettings.ContinueAsyncTasksOnCapturedContext));
            }
            catch (WebException ex)
            {
                if (ex.Status == WebExceptionStatus.ProtocolError)
                {
                    if (ex.Response is HttpWebResponse response)
                    {
                        string responseText;

                        using (var stream = new StreamReader(response.GetResponseStream()))
                        {
                            responseText =
                                await stream.ReadToEndAsync().ConfigureAwait(ConsulClientSettings.ContinueAsyncTasksOnCapturedContext);
                        }

                        throw new ConsulApiException(response.StatusCode, responseText);
                    }

                    throw;
                }

                throw;
            }
        }