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

Hangfire+MailKit邮件任务超时连接失败,直接调用却正常的原因

Hangfire结合MailKit发送邮件时后台任务超时失败,但直接调用正常的问题

问题描述

在ASP.NET Core应用中使用Hangfire+MailKit发送邮件时,遇到以下异常情况:

  • 邮件发送逻辑加入Hangfire后台任务队列后,任务因超时失败,报错:A connection attempt failed because the connected party did not properly respond...
  • 直接在控制器中调用相同的邮件发送逻辑可成功执行,仅连接阶段耗时约3-4分钟。

相关代码

Program.cs中的Hangfire配置

var storageOptions = new SqlServerStorageOptions()
{
    CommandTimeout = TimeSpan.FromMinutes(10),
    CommandBatchMaxTimeout = TimeSpan.FromMinutes(10),
};

builder.Services.AddHangfire(configuration => configuration
    .SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
    .UseSimpleAssemblyNameTypeSerializer()
    .UseRecommendedSerializerSettings()
    .UseSqlServerStorage(builder.Configuration.GetConnectionString("HangfireConnection"), storageOptions));

builder.Services.AddHangfireServer();

邮件发送逻辑

using (var client = new SmtpClient())
{
    client.Timeout = 300000; // 5 minutes

    await client.ConnectAsync(_settings.Server, _settings.Port, _settings.UseSSL);

    if (_settings.RequireAuth)
    {
        await client.AuthenticateAsync(_settings.Username, _settings.Password);
    }

    await client.SendAsync(mimeMessage);
    await client.DisconnectAsync(true);
}

已尝试的操作

  • 将SmtpClient.Timeout调整为5分钟
  • 将SqlServerStorageOptions的CommandTimeout和CommandBatchMaxTimeout调整为10分钟

原因分析及解决方案

1. 异步操作未配置超时令牌

你设置的SmtpClient.Timeout仅对同步操作生效,异步方法(如ConnectAsync)需要通过CancellationToken来控制超时。Hangfire执行异步任务时会默认关联取消令牌,若任务执行时间接近Hangfire内部阈值,可能触发取消导致连接失败。

修改邮件发送代码,添加异步超时令牌:

using (var client = new SmtpClient())
{
    client.Timeout = 300000; // 同步操作超时设为5分钟
    using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5)); // 异步操作超时令牌

    await client.ConnectAsync(_settings.Server, _settings.Port, _settings.UseSSL, cts.Token);

    if (_settings.RequireAuth)
    {
        await client.AuthenticateAsync(_settings.Username, _settings.Password, cts.Token);
    }

    await client.SendAsync(mimeMessage, cts.Token);
    await client.DisconnectAsync(true, cts.Token);
}

2. Hangfire Server配置未适配长耗时任务

Hangfire Server默认的服务器超时(ServerTimeout)和工作线程数可能不适合3-4分钟的长耗时任务,导致任务被误判为失败或无法及时分配线程。

修改Hangfire Server配置:

builder.Services.AddHangfireServer(options =>
{
    // 根据服务器CPU核心数调整工作线程数量,避免线程耗尽
    options.WorkerCount = Environment.ProcessorCount * 2;
    // 延长服务器超时时间,避免长耗时任务被标记为失败
    options.ServerTimeout = TimeSpan.FromMinutes(15);
});

3. 网络上下文差异

控制器运行在Web应用池上下文下,可能继承了系统代理或防火墙规则;而Hangfire后台线程的网络上下文独立,可能因未配置代理导致连接SMTP服务器异常。

排查方向:检查服务器的代理设置,确保Hangfire后台线程能正常访问目标SMTP服务器,必要时在邮件发送逻辑中显式配置代理。

4. 日志排查辅助

开启Hangfire详细日志,记录任务执行的每个阶段耗时,明确超时发生在连接、认证还是发送环节,便于精准定位问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 17:07:11