Ejemplo n.º 1
0
        public async Task <HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
        {
            var itemDictionary = new Dictionary <string, object>();
            HealthCheckResult retval;

            try
            {
                foreach (var trigger in _timerTriggers)
                {
                    if (trigger.IsTimerDisabled)
                    {
                        itemDictionary.Add(trigger.TimerTriggerFriendlyName, new TimerTriggerHealthResult {
                            LastCompletionTime = DateTime.MinValue, LastExpectedCompletionTime = DateTime.MinValue, IsTimerDisabled = true
                        });
                    }
                    else
                    {
                        //get last execution completion time
                        var blobPath       = TimerHealthCheckHelper.GetBlobPath(trigger.TimerFullTypeName, _helperOptions);
                        var lastTimeString = await _blobStorage.DownloadFileAsTextAsync(blobPath).ConfigureAwait(false);

                        TimerHealthCheckStatus status = JsonSerializer.Deserialize <TimerHealthCheckStatus>(lastTimeString);
                        var lastExpectedTime          = GetLastScheduledOccurrence(trigger.ScheduleExpression, _dateTimeService.CurrentDateTimeOffset.DateTime);
                        itemDictionary.Add(trigger.TimerTriggerFriendlyName, new TimerTriggerHealthResult {
                            LastCompletionTime = status.LastCheckpoint, LastExpectedCompletionTime = new DateTimeOffset(lastExpectedTime, status.LastCheckpoint.Offset)
                        });
                    }
                }
                var badTimers = itemDictionary.Where(x => !((TimerTriggerHealthResult)x.Value).IsTimerDisabled && ((((TimerTriggerHealthResult)x.Value).LastCompletionTime) < ((TimerTriggerHealthResult)x.Value).LastExpectedCompletionTime) && _dateTimeService.CurrentDateTimeOffset > ((TimerTriggerHealthResult)x.Value).LastExpectedCompletionTime + _options.ToleranceTimeSpan).Select(x => new { TimerName = x.Key, Result = x.Value as TimerTriggerHealthResult }).ToList();
                if (badTimers.Any())
                {
                    var sb = new StringBuilder();
                    foreach (var item in badTimers)
                    {
                        sb.Append($"Timer {item.TimerName} did not fire on time - LastCompletedTime = {item.Result!.LastCompletionTime} Last Expected Time = {item.Result!.LastExpectedCompletionTime}");
                        sb.Append("\n");
                    }
                    retval = new HealthCheckResult(HealthStatus.Unhealthy, sb.ToString(), null, itemDictionary);
                }
                else
                {
                    retval = new HealthCheckResult(HealthStatus.Healthy, null, null, itemDictionary);
                }
            }
            catch (Exception ex)
            {
                retval = new HealthCheckResult(HealthStatus.Unhealthy, "", ex, itemDictionary);
            }

            return(retval);
        }
        /// <summary>
        /// Call this method at the end of your timer so it can checkpoint successful completion
        /// </summary>
        /// <typeparam name="T">The Type of your timertrigger</typeparam>
        /// <returns></returns>
        public async Task CheckpointMethodAsync <T>()
        {
            var blobContainer = _blobStorageFactory.GetBlobStorage(_options.AzureWebJobsStorageConnectionString, "azure-webjobs-hosts");
            var status        = new TimerHealthCheckStatus {
                LastCheckpoint = _dateTimeService.CurrentDateTimeOffset
            };

            if (_options.IsProductionSlot)
            {
                var blobPath = GetBlobPath(typeof(T).FullName, _options);
                await blobContainer.StoreBlobAsTextAsync(blobPath, JsonSerializer.Serialize(status)).ConfigureAwait(false);

                if (string.IsNullOrWhiteSpace(_options.AzureWebSiteName))
                {
                    _logger.LogWarning("It appears you are running locally. Timer will be checkpointed, but if you are not running locally, make sure you include the APPSETTING_WEBSITE_SITE_NAME to make sure this timer's checkpoint is unique to this instance");
                }
            }
            else
            {
                _logger.LogWarning("Timer is not running in a production slot, timer will not be checkpointed");
            }
        }