Hangfire 重试后发送电子邮件

2023-12-27

我们有几个作业设置为 10 次重试。由于性质或外部服务,有时在第一次或第二次过程中会失败,我们会收到失败电子邮件。但第三次或第四次工作就会成功。现在我想以协调的方式向早期的失败电子邮件发送电子邮件。因此,如果我们连续收到成功的电子邮件,我们可以安全地忽略之前的失败电子邮件。我想按以下模式发送电子邮件标题;所以关联起来变得更容易。

Attempt 1 -> Email Header : JobID - JobName - Attempt 1 - Failed
Attempt 2 -> Email Header : JobID - JobName - Attempt 2 - Failed
Attempt 3 -> Email Header : JobID - JobName - Attempt 3 - Succeeded

如何在hangfire 中实现这一点?我还想检索给定作业的重试尝试次数。

Thanks

到目前为止我的方法。还有其他更好的方法吗?

namespace Forte.Application.Hangfire.Filter
{
    public class HangFireEmailerFilter : JobFilterAttribute, IElectStateFilter
    {
        private readonly IEmailer _emailer;
        private readonly IHangfireEmailSettings _hangfireSettings;

        public HangFireEmailerFilter(IHangfireEmailSettings hangfireSettings)
        {
            _hangfireSettings = hangfireSettings;
            _emailer = new Emailer(hangfireSettings);
        }

        public void OnStateElection(ElectStateContext context)
        {
            if(context?.CandidateState is FailedState || context?.CandidateState is SucceededState)
            {
                if(_hangfireSettings.IsEnabled)
                { 
                    var emailHeader = string.Empty;
                    var body = string.Empty;
                    int? totalAttemptsAllowed = null;
                    var highPriority = false;
                    var sendEmail = false;

                    var currentRetryCount = context.GetJobParameter<int>("RetryCount");
                    var retryAttribute = (AutomaticRetryAttribute) GetCustomAttribute(context.BackgroundJob.Job.Type, typeof(AutomaticRetryAttribute));

                    var jobId = context.BackgroundJob.Id;

                    if(retryAttribute != null)
                    { 
                        totalAttemptsAllowed = retryAttribute.Attempts;
                    }

                    if (context.CandidateState is FailedState failedState)
                    {
                        //FATAL
                        if(totalAttemptsAllowed.HasValue && currentRetryCount == totalAttemptsAllowed)
                        {
                            emailHeader = $"{EmailLevel.FATAL.ToString()}:{GetEmailSubject(context, currentRetryCount, totalAttemptsAllowed, jobId)}";
                            highPriority = true;
                        }
                        //ERROR
                        else 
                        {
                            emailHeader = $"{EmailLevel.FAIL.ToString()}:{GetEmailSubject(context, currentRetryCount, totalAttemptsAllowed, jobId)}";
                        }
                        body =  _hangfireSettings.JobDashboardUrl + jobId + "\n\n" + failedState.Exception.Message;
                        sendEmail = true;
                    }

                    if (context.CandidateState is SucceededState)
                    {
                        if(currentRetryCount > 1) //OK
                        {
                            emailHeader = $"{EmailLevel.OK.ToString()}:{GetEmailSubject(context, currentRetryCount, totalAttemptsAllowed, jobId)}";
                            body = $"{_hangfireSettings.JobDashboardUrl + jobId} {Environment.NewLine} Job Completed.";
                            sendEmail = true;
                        }
                    }

                    if(sendEmail)
                    { 
                        _emailer.SendEmail(_hangfireSettings.FromEmail, _hangfireSettings.ToEmail, emailHeader, body, highPriority);
                    }
                }
            }
        }

        private string GetEmailSubject(ElectStateContext context, int retryCount, int? totalAttemptsAllowed, string jobId)
        {
            if(totalAttemptsAllowed.HasValue)
            { 
                return $"{context.BackgroundJob.Job.Type.Name}.{context.BackgroundJob.Job.Method.Name} " +
                       $"[{jobId}:{retryCount}/{totalAttemptsAllowed.Value}][{_hangfireSettings.ProcessName}][{_hangfireSettings.MachineName}]";
            }
            else
            {
                return $"{context.BackgroundJob.Job.Type.Name}.{context.BackgroundJob.Job.Method.Name} " +
                       $"[{jobId}:{retryCount}][{_hangfireSettings.ProcessName}][{_hangfireSettings.MachineName}]";
            }
        }
    }
}

None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Hangfire 重试后发送电子邮件 的相关文章

  • 以相反的顺序迭代可变参数模板参数

    如果我手动反转传递给它的模板参数的顺序 以下代码将起作用 template
  • C 中的变量定义是什么意思[重复]

    这个问题在这里已经有答案了 你们能告诉我 这在 C 中意味着什么吗 define Privileged Data Privileged Data static int dVariable 编译器对变量进行寻址有特殊意义吗 这只是一个宏Pri
  • SetWindowsHookEx 函数返回 NULL

    我正在研究 DLL 注入 但收到错误如下 挂接进程失败 87 参数不正确 目标进程和dll都是64位的 注入代码为 BOOL HookInjection TCHAR target TCHAR dll name https msdn micr
  • 为什么opencv videowriter这么慢?

    你好 stackoverflow 社区 我有一个棘手的问题 我需要你的帮助来了解这里发生了什么 我的程序从视频采集卡 Blackmagic 捕获帧 到目前为止 它工作得很好 同时我用 opencv cv imshow 显示捕获的图像 它也工
  • 没有 Unicode 字节顺序标记。无法切换到 Unicode

    我正在使用 XSD 编写 XML 验证器 下面是我所做的 但是当验证器到达该线时while list Read 它给了我错误 没有 Unicode 字节顺序标记 无法切换到 Unicode 有人可以帮我解决吗 public class Va
  • 切换图片框可见性 C#

    为什么图片框控件的可见性属性在这里不起作用 我最初将它们设置为 false 以便在屏幕加载时它们不可见 但后来我想切换这个 我已完成以下操作 但似乎不起作用 这是一个 Windows 窗体应用程序 private void Action w
  • WebClient读取错误页面的内容

    我有一个加载页面内容的应用程序 我使用 WebClient 类 即使服务器返回 404 500 等错误 我也需要检索内容 我需要这样的东西 WebClient wc new WebClient string pageContent try
  • 通过单个 GPIO 引脚转储闪存

    我正在使用 Infineon 的 XMC4500 Relax Kit 并尝试通过单个 GPIO 引脚提取固件 我非常天真的想法是通过 GPIO 引脚一次转储一位 然后用逻辑分析仪以某种方式 嗅探 数据 伪代码 while word by w
  • 使用 openssl 检查服务器安全协议

    我有一个框架应用程序 它根据使用方式连接到不同的服务器 对于 https 连接 使用 openssl 我的问题是 我需要知道我连接的服务器是否使用 SSL 还是 TLS 以便我可以创建正确的 SSL 上下文 目前 如果我使用错误的上下文尝试
  • QThread - 使用槽 quit() 退出线程

    我想在线程完成运行时通知对象 但是 我无法让线程正确退出 我有以下代码 处理器 cpp thread new QThread tw new ThreadWorker connect tw SIGNAL updateStatus QStrin
  • c# 如何生成锦标赛括号 HTML 表

    所以我已经被这个问题困扰了三个星期 但我一生都无法弄清楚 我想做的是使用表格获得这种输出 演示 http www esl world net masters season6 hanover sc2 playoffs rankings htt
  • Dynamics Crm:获取状态代码/状态代码映射的元数据

    在 Dynamics CRM 2011 中 在事件实体上 状态原因 选项集 也称为状态代码 与 状态 选项集 也称为状态代码 相关 例如看这个截图 当我使用 API 检索状态原因选项集时 如下所示 RetrieveAttributeRequ
  • 将 bignum 类型结构转换为人类可读字符串的有效方法是什么?

    我有一点问题 为了增长我的 C 知识 我决定尝试实现一个基本的 bigint 库 bigint 结构的核心将是一个 32 位整数数组 选择它们是因为它们适合寄存器 这将允许我在数字之间进行操作 这些操作将在 64 位整数中溢出 这也将适合寄
  • 你能解释一下这个C++删除问题吗?

    我有以下代码 std string F WideString ws GetMyWideString std string ret StringUtils ConvertWideStringToUTF8 ws ret return ret W
  • 是否有任何不使用公共虚拟方法的正当理由? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 是否有任何不使用公共虚拟方法的正当理由 我在某处读到我们应该避免使用公共虚拟方法 但我想向专家确认这是否是有效的声明 对于良好且稳定的 API
  • 将一个 long 转换为两个 int 以进行重构

    我需要将一个参数作为两个 int 参数传递给 Telerik Report 因为它不能接受长参数 将 long 拆分为两个 int 并在不丢失数据的情况下重建它的最简单方法是什么 使用掩蔽和移位是最好的选择 根据文档 long 保证为 64
  • 如何强制执行特定的 UserControl 设计

    我正在编写一个基本用户控件 它将由一堆其他用户控件继承 我需要对所有这些后代控件强制执行某种设计 例如 顶部必须有几个按钮以及一个或两个标签 后代用户控件区域的其余部分可以自由放置任何内容 最初 我认为我可以将一个面板放到 Base Use
  • 在何处将 CFLAG(例如 -std=gnu99)添加到 (Eclipse CDT) 自动工具项目中

    我有一个简单的 Autotools C 项目 不是 C 其框架是由 Eclipse CDT Juno 为我创建的 CFLAG 通过检查 似乎是 g O2 我希望所有生成的 make 文件也具有 std gnu99附加到 CFLAG 因为我使
  • 通过 cmake 链接作为外部项目包含的 opencv 库[重复]

    这个问题在这里已经有答案了 我对 cmake 比较陌生 经过几天的努力无法弄清楚以下事情 我有一个依赖于 opencv 的项目 它本身就是一个 cmake 项目 我想静态链接 opencv 库 我正在做的是我的项目中有一份 opencv 源
  • 创建带有部分的选项卡式侧边栏 WPF

    我正在尝试创建一个带有部分的选项卡式侧边栏 如 WPF 中的以下内容 我考虑过几种方法 但是有没有更简单 更优雅的方法呢 方法一 列表框 Using a ListBox并将 SelectedItem 绑定到右侧内容控件所绑定的值 为了区分标

随机推荐