仅当作业重试用尽且作业进入“失败”状态时,Application Insights 的 Hangfire 作业筛选器才应记录

Hangfire job filter for Application Insights should log only when job retries are exhausted and the job moves to Failed state

提问人:nop 提问时间:11/14/2023 更新时间:11/14/2023 访问量:52

问:

我正在使用以下 Hangfire 作业筛选器在 Application Insights 中记录作业执行。我的目标是在所有重试用尽后,为最终失败的作业创建警报。但是,我遇到了一个问题,即 Application Insights 会记录引发的每个异常,即使 Hangfire 要重试作业也是如此。这会导致过早的警报,因为我只想在作业进入 Hangfire 中的“失败”选项卡时进行记录,这意味着它已停止重试并且确实失败了。

下面是我用来记录作业的 HangfireApplicationInsightsFilter 类:

public sealed class HangfireApplicationInsightsFilter : IServerFilter
{
    private readonly TelemetryClient _telemetryClient;

    public HangfireApplicationInsightsFilter(TelemetryClient telemetryClient) => _telemetryClient = telemetryClient;

    public void OnPerforming(PerformingContext filterContext)
    {
        var operation = _telemetryClient.StartOperation<RequestTelemetry>(GetJobName(filterContext.BackgroundJob));
        operation.Telemetry.Properties.Add("JobId", filterContext.BackgroundJob.Id);
        operation.Telemetry.Properties.Add("Arguments", GetJobArguments(filterContext.BackgroundJob));

        filterContext.Items["ApplicationInsightsOperation"] = operation;
    }

    public void OnPerformed(PerformedContext filterContext)
    {
        if (filterContext.Items["ApplicationInsightsOperation"] is not IOperationHolder<RequestTelemetry> operation) return;

        if (filterContext.Exception == null || filterContext.ExceptionHandled)
        {
            operation.Telemetry.Success = true;
            operation.Telemetry.ResponseCode = "Success";
        }
        else
        {
            operation.Telemetry.Success = false;
            operation.Telemetry.ResponseCode = "Failed";

            var operationId = operation.Telemetry.Context.Operation.Id;

            var exceptionTelemetry = new ExceptionTelemetry(filterContext.Exception);
            exceptionTelemetry.Context.Operation.Id = operationId;
            exceptionTelemetry.Context.Operation.ParentId = operationId;

            _telemetryClient.TrackException(exceptionTelemetry);
        }

        _telemetryClient.StopOperation(operation);
    }

    private static string GetJobName(BackgroundJob backgroundJob) => $"{backgroundJob.Job.Type.Name}.{backgroundJob.Job.Method.Name}";

    private static string GetJobArguments(BackgroundJob backgroundJob) => JsonSerializer.Serialize(backgroundJob.Job.Args);
}

此筛选器会记录每个异常,即使重试作业也是如此。我需要的是仅在最后一次重试失败后才记录异常。

如何修改我的“HangfireApplicationInsightsFilter”,使其仅在 Hangfire 停止重试作业并且作业移动到“失败”状态时才记录异常?

有关如何实现此行为的任何指导或见解将不胜感激。

C# ASP.net-core azure-application-insights hangfire

评论


答:

1赞 Eldar 11/14/2023 #1

您可以创建一个实现接口的过滤器,如下所示:IApplyStateFilter

public sealed class HangfireApplicationInsightsFilter : IServerFilter, IApplyStateFilter
{
 // .. the other implementations
 public void OnStateApplied(ApplyStateContext context, IWriteOnlyTransaction transaction)
 {
     Logger.DebugFormat(
         "Job `{0}` state was changed from `{1}` to `{2}`",
         context.BackgroundJob.Id,
         context.OldStateName,
         context.NewState.Name);

   if (context.NewState is FailedState failed)
   {
     // do something with failed state.
   }
  }
}

评论

0赞 nop 11/14/2023
谢谢!我无法访问 .我该怎么做?我需要将操作存储在某个地方context.Items
1赞 Eldar 11/14/2023
@nop 这属于 当状态类似于PerformContextEnqueuedState context.CustomData["ApplicationInsightsOperation"] = operation;
0赞 nop 11/15/2023
谢谢,我用一个做了,明天会测试并接受答案。希望这能奏效ConcurrentDictionary