private async Task DoLongPollingRefresh(string appId, string cluster, string dataCenter, CancellationToken cancellationToken)
        {
            var        random         = new Random();
            ServiceDto lastServiceDto = null;

            while (!cancellationToken.IsCancellationRequested)
            {
                var    sleepTime = 50; //default 50 ms
                string url       = null;
                try
                {
                    if (lastServiceDto == null)
                    {
                        var configServices = await _serviceLocator.GetConfigServices().ConfigureAwait(false);

                        lastServiceDto = configServices[random.Next(configServices.Count)];
                    }

                    url = AssembleLongPollRefreshUrl(lastServiceDto.HomepageUrl, appId, cluster, dataCenter);

                    Logger().Debug($"Long polling from {url}");

                    var response = await _httpUtil.DoGetAsync <IList <ApolloConfigNotification> >(url, 600000).ConfigureAwait(false);

                    Logger().Debug($"Long polling response: {response.StatusCode}, url: {url}");
                    if (response.StatusCode == HttpStatusCode.OK && response.Body != null)
                    {
                        UpdateNotifications(response.Body);
                        UpdateRemoteNotifications(response.Body);
                        Notify(lastServiceDto, response.Body);
                        _longPollSuccessSchedulePolicyInMs.Success();
                    }
                    else
                    {
                        sleepTime = _longPollSuccessSchedulePolicyInMs.Fail();
                    }

                    //try to load balance
                    if (response.StatusCode == HttpStatusCode.NotModified && random.NextDouble() >= 0.5)
                    {
                        lastServiceDto = null;
                    }

                    _longPollFailSchedulePolicyInSecond.Success();
                }
                catch (Exception ex)
                {
                    lastServiceDto = null;

                    var sleepTimeInSecond = _longPollFailSchedulePolicyInSecond.Fail();
                    Logger().Warn($"Long polling failed, will retry in {sleepTimeInSecond} seconds. appId: {appId}, cluster: {cluster}, namespace: {string.Join(ConfigConsts.ClusterNamespaceSeparator, _longPollNamespaces.Keys)}, long polling url: {url}, reason: {ex.GetDetailMessage()}");

                    sleepTime = sleepTimeInSecond * 1000;
                }
                finally
                {
                    await Task.Delay(sleepTime, cancellationToken).ConfigureAwait(false);
                }
            }
        }
예제 #2
0
        private async Task <ApolloConfig?> LoadApolloConfig(bool isFirst)
        {
            var appId      = _options.AppId;
            var cluster    = _options.Cluster;
            var dataCenter = _options.DataCenter;

            var configServices = await _serviceLocator.GetConfigServices().ConfigureAwait(false);

            Exception?exception = null;
            string?   url       = null;

            var notFound = false;

            for (var i = 0; i < (isFirst ? 1 : 2); i++)
            {
                IList <ServiceDto> randomConfigServices = new List <ServiceDto>(configServices);
                randomConfigServices.Shuffle();

                //Access the server which notifies the client first
                var longPollServiceDto = Interlocked.Exchange(ref _longPollServiceDto, null);
                if (longPollServiceDto != null)
                {
                    randomConfigServices.Insert(0, longPollServiceDto);
                }

                foreach (var configService in randomConfigServices)
                {
                    url = AssembleQueryConfigUrl(configService.HomepageUrl, appId, cluster, Namespace, dataCenter, _remoteMessages !, _configCache !);

                    Logger().Debug($"Loading config from {url}");

                    try
                    {
                        var response = await _httpUtil.DoGetAsync <ApolloConfig>(url).ConfigureAwait(false);

                        if (response.StatusCode == HttpStatusCode.NotModified)
                        {
                            Logger().Debug("Config server responds with 304 HTTP status code.");
                            return(_configCache !);
                        }

                        var result = response.Body;

                        Logger().Debug(
                            $"Loaded config for {Namespace}: {result?.Configurations?.Count ?? 0}");

                        return(result);
                    }
                    catch (ApolloConfigStatusCodeException ex)
                    {
                        var statusCodeException = ex;
                        //config not found
                        if (ex.StatusCode == HttpStatusCode.NotFound)
                        {
                            notFound = true;

                            var message = $"Could not find config for namespace - appId: {appId}, cluster: {cluster}, namespace: {Namespace}, please check whether the configs are released in Apollo!";
                            statusCodeException = new ApolloConfigStatusCodeException(ex.StatusCode, message);
                        }

                        Logger().Warn(statusCodeException);
                        exception = statusCodeException;
                    }
                    catch (Exception ex)
                    {
                        Logger().Warn(ex);
                        exception = ex;
                    }
                }
#if NET40
                await TaskEx.Delay(1000).ConfigureAwait(false);
#else
                await Task.Delay(1000).ConfigureAwait(false);
#endif
            }

            if (notFound)
            {
                return(null);
            }

            var fallbackMessage = $"Load Apollo Config failed - appId: {appId}, cluster: {cluster}, namespace: {Namespace}, url: {url}";

            throw new ApolloConfigException(fallbackMessage, exception !);
        }