private async Task <HealthCheckResult> CheckHealthAsync(HealthCheckPolicy policy, IHealthCheckSettings settings) { var checkCache = _resultCache[settings.Name]; var utcNow = _clock.UtcNow; HealthCheckResult result = null; if (!checkCache.ShouldCheck(utcNow)) { result = checkCache.Result; } else { using (CancellationTokenSource cts = new CancellationTokenSource(settings.Timeout)) { IHealthCheck check = checkCache.Check; var healthContext = new HealthCheckContext(settings); healthContext.CancellationToken = cts.Token; try { await check.CheckHealthAsync(healthContext); result = new HealthCheckResult { Name = settings.Name, Elapsed = healthContext.ElapsedMilliseconds, Message = healthContext.Message, Status = healthContext.HasSucceeded ? HealthStatus.Healthy : healthContext.HasWarned ? HealthStatus.Warning : HealthStatus.Unhealthy, Issued = utcNow.ToUnixTimeSeconds(), NextTry = utcNow.AddSeconds(settings.Frequency), Critical = settings.Critical, Properties = healthContext.Properties?.ToDictionary(kvp => kvp.Key, kvp => JToken.FromObject(kvp.Value)) }; checkCache.Result = result; } catch (Exception e) { result = new HealthCheckResult { Name = settings.Name, Elapsed = healthContext.ElapsedMilliseconds, Message = "An error occured. See logs for more details.", Status = HealthStatus.Unhealthy, Issued = utcNow.ToUnixTimeSeconds(), NextTry = utcNow.AddSeconds(settings.Frequency), Critical = settings.Critical, Exception = e }; checkCache.Result = result; } } } return(result); }
public DefaultHealthCheckPolicyProvider(HealthCheckPolicy defaultPolicy) { if (defaultPolicy == null) { throw new ArgumentNullException(nameof(defaultPolicy)); } DefaultPolicy = defaultPolicy; _policies = CreatePolicies(defaultPolicy); }
public async Task <HealthCheckResponse> CheckHealthAsync(HealthCheckPolicy policy) { var taskResults = new Task <HealthCheckResult> [policy.CheckSettings.Count]; for (int i = 0; i < policy.CheckSettings.Count; i++) { var settings = policy.CheckSettings[i].Value; taskResults[i] = Task.Run(() => CheckHealthAsync(policy, settings)); } var results = await Task.WhenAll(taskResults); return(new HealthCheckResponse(results)); }
private Dictionary <string, HealthCheckPolicy> CreatePolicies(HealthCheckPolicy policy) { var policies = policy.CheckSettings .SelectMany(s => s.Value.Tags, (s, t) => new { Tag = t, Settings = s }) .GroupBy(item => item.Tag) .ToDictionary( group => group.Key, group => group.Aggregate(new HealthCheckSettingsCollection(), (settings, item) => { settings.Add(item.Settings); return(settings); }, settings => new HealthCheckPolicy(settings))); return(policies); }
public DefaultHealthCheckService(ISystemClock clock, IHealthCheckPolicyProvider policyProvider, ICheckFactory checkFactory) { if (checkFactory == null) { throw new ArgumentNullException(nameof(checkFactory)); } if (clock == null) { throw new ArgumentNullException(nameof(clock)); } if (policyProvider == null) { throw new ArgumentNullException(nameof(policyProvider)); } _checkFactory = checkFactory; _clock = clock; _defaultPolicy = policyProvider.DefaultPolicy; _resultCache = CreateCache(); }
public async Task Invoke(HttpContext context) { PathString subpath; if (!context.Request.Path.StartsWithSegments(_options.Path, out subpath)) { await _next(context); return; } var policyName = subpath.ToUriComponent().Trim('/'); if (policyName.Length == 0) { policyName = Constants.DefaultPolicy; } if (_options.AuthorizationPolicy != null) { var principal = await SecurityHelper.GetUserPrincipal(context, _options.AuthorizationPolicy); if (!await _authorizationService.AuthorizeAsync(principal, context, _options.AuthorizationPolicy)) { _logger.AuthorizationFailed(); await _next(context); return; } } HealthCheckPolicy policy = _policyProvider.GetPolicy(policyName); if (policy == null) { _logger.InvalidPolicy(policyName); await _next(context); return; } var response = context.Response; var healthCheckResponse = await _healthService.CheckHealthAsync(policy); if (healthCheckResponse.HasErrors) { _logger.HealthCheckFailed(healthCheckResponse.Errors); if (healthCheckResponse.HasCriticalErrors) { response.StatusCode = StatusCodes.Status503ServiceUnavailable; response.WriteRetryAfterHeader(healthCheckResponse.RetryAfter); } } else { _logger.HealthCheckSucceeded(); response.StatusCode = StatusCodes.Status200OK; } if (_options.SendResults && !HttpMethods.IsHead(context.Request.Method)) { response.ContentType = ApplicationJson; using (var writer = new HttpResponseStreamWriter(response.Body, Encoding.UTF8, 1024, _bytePool, _charPool)) { using (var jsonWriter = new JsonTextWriter(writer)) { jsonWriter.ArrayPool = _jsonCharPool; jsonWriter.CloseOutput = false; _jsonSerializer.Serialize(jsonWriter, healthCheckResponse.Results); } } } }
public CanaryMiddleware( RequestDelegate next, IOptions <CanaryOptions> options, ILoggerFactory loggerFactory, IHealthCheckService healthService, IHealthCheckPolicyProvider policyProvider, IServerSwitch serverSwitch, IAuthorizationService authorizationService) { if (next == null) { throw new ArgumentNullException(nameof(next)); } if (options == null) { throw new ArgumentNullException(nameof(options)); } if (loggerFactory == null) { throw new ArgumentNullException(nameof(loggerFactory)); } if (healthService == null) { throw new ArgumentNullException(nameof(healthService)); } if (policyProvider == null) { throw new ArgumentNullException(nameof(policyProvider)); } if (authorizationService == null) { throw new ArgumentNullException(nameof(authorizationService)); } if (authorizationService == null) { throw new ArgumentNullException(nameof(authorizationService)); } _next = next; _options = options.Value; _logger = loggerFactory.CreateLogger <CanaryMiddleware>(); _healthService = healthService; _serverSwitch = serverSwitch; _authorizationService = authorizationService; if (_options.EnableHealthCheck) { var defaultPolicy = policyProvider.GetPolicy(_options.PolicyName); if (defaultPolicy == null) { throw new ArgumentException($"{nameof(_options.PolicyName)} '{_options.PolicyName}' is not a valid policy.", nameof(_options)); } _defaultPolicy = defaultPolicy; } }