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

如何在Hangfire中配置速率限制以适配邮件服务的限流规则?

在Hangfire中配置邮件发送的速率限制方案

完全可以在Hangfire中配置速率限制,确保邮件发送不超出服务商的每分钟100封、每小时1000封限制,以下是两种实用实现方式:

方式一:使用第三方限流扩展

通过Hangfire.RateLimit包可以快速实现多维度速率限制:

  1. 安装NuGet包:
Install-Package Hangfire.RateLimit
  1. 在Hangfire配置中添加限流规则:
services.AddHangfire(config =>
{
    config.UseRateLimiter(new RateLimiterOptions
    {
        Limits = new List<RateLimit>
        {
            // 每分钟100封限制
            new RateLimit
            {
                Key = "email-job",
                Period = TimeSpan.FromMinutes(1),
                Limit = 100
            },
            // 每小时1000封限制
            new RateLimit
            {
                Key = "email-job",
                Period = TimeSpan.FromHours(1),
                Limit = 1000
            }
        }
    });
});
  1. 给邮件发送任务标记限流键:
[RateLimit("email-job")]
public async Task SendEmailAsync(string to, string subject, string body)
{
    // 邮件服务发送逻辑
}

方式二:自定义限流过滤器(无依赖)

如果不想引入第三方包,可通过Hangfire的JobFilterAttribute自定义限流逻辑,结合缓存实现计数控制:

  1. 实现自定义限流过滤器:
public class EmailRateLimitFilter : JobFilterAttribute, IElectStateFilter
{
    private readonly IDistributedCache _distributedCache;

    public EmailRateLimitFilter(IDistributedCache distributedCache)
    {
        _distributedCache = distributedCache;
    }

    public async void OnStateElection(ElectStateContext context)
    {
        var now = DateTime.UtcNow;
        var minuteKey = $"email-limit:minute:{now:yyyyMMddHHmm}";
        var hourKey = $"email-limit:hour:{now:yyyyMMddHH}";

        // 检查分钟限制
        var minuteCount = await _distributedCache.GetAsync<int>(minuteKey) ?? 0;
        if (minuteCount >= 100)
        {
            context.CandidateState = new ScheduledState(TimeSpan.FromMinutes(1))
            {
                Reason = "触发每分钟邮件限制,延迟执行"
            };
            return;
        }

        // 检查小时限制
        var hourCount = await _distributedCache.GetAsync<int>(hourKey) ?? 0;
        if (hourCount >= 1000)
        {
            context.CandidateState = new ScheduledState(TimeSpan.FromHours(1))
            {
                Reason = "触发每小时邮件限制,延迟执行"
            };
            return;
        }

        // 更新计数
        await _distributedCache.SetAsync(minuteKey, minuteCount + 1, new DistributedCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1)
        });
        await _distributedCache.SetAsync(hourKey, hourCount + 1, new DistributedCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
        });
    }
}
  1. 注册过滤器到Hangfire:
services.AddHangfire(config =>
{
    config.GlobalJobFilters.Add(new EmailRateLimitFilter(serviceProvider.GetRequiredService<IDistributedCache>()));
});
  1. 也可为单个任务单独应用过滤器:
BackgroundJob.Enqueue<EmailService>(x => x.SendEmailAsync(to, subject, body))
    .WithFilter(new EmailRateLimitFilter(distributedCache));

注意事项

  • 分布式部署场景下,必须使用Redis等分布式缓存替代内存缓存,避免多节点计数不一致
  • 需处理任务重试逻辑,可在过滤器中判断任务是否为重试,避免重复计数
  • 建议将邮件任务分配到专属队列,便于单独管控限流规则

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 22:42:42