示例#1
0
        /// <summary>
        /// Loads (or reloads) the data for this provider.
        /// </summary>
        public async Task <IDictionary <string, string> > LoadAsync(CancellationToken cancellationToken)
        {
            var data = new Dictionary <string, string>();

            IEnumerable <ApplicationWrapper> applications;

            try
            {
                applications = await _serviceFabricCaller.GetApplicationListAsync(cancellationToken);
            }
            catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested)
            {
                throw;
            }
            catch (Exception ex) // TODO: davidni: not fatal?
            {
                // The serviceFabricCaller does their best effort to use LKG information, nothing we can do at this point
                _logger.LogError(ex, "Could not get applications list from Service Fabric, continuing with zero applications.");
                applications = Enumerable.Empty <ApplicationWrapper>();
            }

            foreach (var application in applications)
            {
                await LoadApplicationDataAsync(data, application, cancellationToken);
            }

            return(data);
        }
示例#2
0
        /// <inheritdoc/>
        public async Task <(IReadOnlyList <RouteConfig> Routes, IReadOnlyList <ClusterConfig> Clusters)> DiscoverAsync(CancellationToken cancellation)
        {
            // Take a snapshot of current options and use that consistently for this execution.
            var options = _optionsMonitor.CurrentValue;

            _serviceFabricCaller.CleanUpExpired();

            var discoveredBackends = new Dictionary <string, ClusterConfig>(StringComparer.Ordinal);
            var discoveredRoutes   = new List <RouteConfig>();
            IEnumerable <ApplicationWrapper> applications;

            try
            {
                applications = await _serviceFabricCaller.GetApplicationListAsync(cancellation);
            }
            catch (OperationCanceledException) when(cancellation.IsCancellationRequested)
            {
                throw;
            }
            catch (Exception ex) // TODO: davidni: not fatal?
            {
                // The serviceFabricCaller does their best effort to use LKG information, nothing we can do at this point
                Log.GettingApplicationFailed(_logger, ex);
                applications = Enumerable.Empty <ApplicationWrapper>();
            }

            foreach (var application in applications)
            {
                IEnumerable <ServiceWrapper> services;

                try
                {
                    services = await _serviceFabricCaller.GetServiceListAsync(application.ApplicationName, cancellation);
                }
                catch (OperationCanceledException) when(cancellation.IsCancellationRequested)
                {
                    throw;
                }
                catch (Exception ex) // TODO: davidni: not fatal?
                {
                    Log.GettingServiceFailed(_logger, application.ApplicationName, ex);
                    continue;
                }

                foreach (var service in services)
                {
                    try
                    {
                        var serviceExtensionLabels = await _serviceFabricExtensionConfigProvider.GetExtensionLabelsAsync(application, service, cancellation);

                        // If this service wants to use us as the proxy
                        if (serviceExtensionLabels.GetValueOrDefault("YARP.Enable", null) != "true")
                        {
                            // Skip this service
                            continue;
                        }

                        var destinations = await DiscoverDestinationsAsync(options, service, serviceExtensionLabels, cancellation);

                        var cluster = LabelsParser.BuildCluster(service.ServiceName, serviceExtensionLabels, destinations);
                        var clusterValidationErrors = await _configValidator.ValidateClusterAsync(cluster);

                        if (clusterValidationErrors.Count > 0)
                        {
                            throw new ConfigException($"Skipping cluster id '{cluster.ClusterId} due to validation errors.", new AggregateException(clusterValidationErrors));
                        }

                        if (!discoveredBackends.TryAdd(cluster.ClusterId, cluster))
                        {
                            throw new ConfigException($"Duplicated cluster id '{cluster.ClusterId}'. Skipping repeated definition, service '{service.ServiceName}'");
                        }

                        var routes = LabelsParser.BuildRoutes(service.ServiceName, serviceExtensionLabels);
                        var routeValidationErrors = new List <Exception>();
                        foreach (var route in routes)
                        {
                            routeValidationErrors.AddRange(await _configValidator.ValidateRouteAsync(route));
                        }

                        if (routeValidationErrors.Count > 0)
                        {
                            // Don't add ANY routes if even a single one is bad. Trying to add partial routes
                            // could lead to unexpected results (e.g. a typo in the configuration of higher-priority route
                            // could lead to a lower-priority route being selected for requests it should not be handling).
                            throw new ConfigException($"Skipping ALL routes for cluster id '{cluster.ClusterId} due to validation errors.", new AggregateException(routeValidationErrors));
                        }

                        discoveredRoutes.AddRange(routes);

                        ReportServiceHealth(options, service.ServiceName, HealthState.Ok, $"Successfully built cluster '{cluster.ClusterId}' with {routes.Count} routes.");
                    }
                    catch (ConfigException ex)
                    {
                        // User error
                        Log.InvalidServiceConfig(_logger, service.ServiceName, ex);

                        // TODO: emit Error health report once we are able to detect config issues *during* (as opposed to *after*) a target service upgrade.
                        // Proactive Error health report would trigger a rollback of the target service as desired. However, an Error report after rhe fact
                        // will NOT cause a rollback and will prevent the target service from performing subsequent monitored upgrades to mitigate, making things worse.
                        ReportServiceHealth(options, service.ServiceName, HealthState.Warning, $"Could not load service configuration: {ex.Message}.");
                    }
                    catch (Exception ex) // TODO: davidni: not fatal?
                    {
                        // Not user's problem
                        Log.ErrorLoadingServiceConfig(_logger, service.ServiceName, ex);
                    }
                }
            }

            Log.ServiceDiscovered(_logger, discoveredBackends.Count, discoveredRoutes.Count);
            return(discoveredRoutes, discoveredBackends.Values.ToList());
        }