You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改Hangfire Application Insights过滤器仅记录耗尽重试后的失败作业

问题

我正在使用以下Hangfire作业过滤器在Application Insights中记录作业执行情况,目标是为所有重试耗尽后最终失败的作业创建告警。但目前遇到问题:即使Hangfire将重试作业,Application Insights仍会记录每次抛出的异常,导致提前触发告警。我希望仅在作业进入Hangfire的「Failed」标签(即已停止重试、真正失败)时才记录异常。

当前使用的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);
}

解决方案

核心思路是利用Hangfire的IFailureFilter接口——该接口的OnFailed方法仅在作业最终失败(重试次数耗尽,被移入「Failed」标签)时触发,而非每次重试失败都触发。我们可以修改过滤器,将异常记录逻辑移至IFailureFilter的实现中,避免提前记录重试阶段的异常。

修改后的代码

public sealed class HangfireApplicationInsightsFilter : IServerFilter, IFailureFilter
{
    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";
        }

        _telemetryClient.StopOperation(operation);
    }

    // 仅在作业最终失败(重试耗尽)时触发
    public void OnFailed(FailedContext filterContext)
    {
        var exceptionTelemetry = new ExceptionTelemetry(filterContext.Exception);
        // 添加作业元数据便于排查
        exceptionTelemetry.Properties.Add("JobId", filterContext.BackgroundJob.Id);
        exceptionTelemetry.Properties.Add("JobName", GetJobName(filterContext.BackgroundJob));
        exceptionTelemetry.Properties.Add("Arguments", GetJobArguments(filterContext.BackgroundJob));

        _telemetryClient.TrackException(exceptionTelemetry);
    }

    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);
}

关键改动说明

  1. 实现IFailureFilter接口:新增OnFailed方法,该方法由Hangfire在作业最终失败时自动调用,确保仅记录真正需要告警的异常。
  2. 调整OnPerformed逻辑:移除原有的异常记录代码,仅保留作业执行状态的标记(成功/失败),避免重试阶段的异常被提前上报。
  3. 补充元数据:在OnFailed中为异常遥测添加作业ID、名称、参数等信息,方便后续排查问题。

额外注意

确保Hangfire已正确注册该过滤器,例如在Startup中:

services.AddHangfire(config =>
{
    // 其他配置...
    config.UseFilter(new HangfireApplicationInsightsFilter(telemetryClient));
});

内容的提问来源于stack exchange,提问作者nop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 10:45:10