Sidekiq Delay Extension 部分邮件任务未生成邮件问题排查
问题原因排查与解决方案
最高概率原因:Mailer方法静默返回未触发邮件发送
Sidekiq的DelayedMailer扩展执行逻辑为:仅当Mailer方法返回合法的Mail::Message对象时才会触发实际投递,如果方法执行过程中出现以下情况,会直接结束任务,不会抛异常也不会发邮件,耗时仅几毫秒,完全符合你观测到的现象:
- Mailer逻辑中没有显式调用
mail方法,或者条件分支未走到mail调用逻辑 - 代码隐式返回了非邮件对象(比如最后一行是
@events = xxx这类赋值操作,刚好没有走到后面的mail调用) - 全局邮件拦截器/过滤器命中了收件人,直接返回了
ActionMailer::Base::NullMail对象 - 执行过程中抛出的异常被全局异常处理逻辑静默吞吃,没有上报到Sidekiq
其他可能原因
- sidekiq-unique-jobs服务端校验逻辑跳过任务:你观测到的仅为客户端入队时的冲突日志,服务端执行前如果校验到锁已过期/不存在,部分版本的sidekiq-unique-jobs会直接跳过任务执行且不会打印你提到的冲突日志,仅标记任务为完成。
- 读写分离同步延迟:如果你的数据库使用了读写分离架构,任务执行时读库还未同步到Campaign的写入数据,
Campaign.find抛出ActiveRecord::RecordNotFound异常,而该异常被你配置的Sidekiq异常过滤规则静默处理,没有重试也没有打错误日志。 - 批量入队参数异常:高并发入队时如果外层的
campaign_id/step变量是可变引用,可能出现部分任务参数异常,但你日志中显示参数正确,该概率极低。 - Redis负载异常:2万条任务对于Sidekiq属于极低负载,除非你的Redis实例同时有其他大流量操作导致响应超时,但这类问题一般会导致任务入队失败而非执行异常,概率极低。
排查步骤
- 给Mailer方法加全链路日志和异常捕获,确认每一步执行状态:
class CampaignMailer < ApplicationMailer def step(campaign_id, step_name, email, first_name) Rails.logger.info "[CampaignMailer] 执行开始: 活动ID=#{campaign_id}, 步骤=#{step_name}, 收件人=#{email}" begin @campaign = Campaign.find(campaign_id) Rails.logger.info "[CampaignMailer] 活动查询成功: 活动ID=#{@campaign.id}" @events = @campaign.events.future Rails.logger.info "[CampaignMailer] 关联活动事件数量: #{@events.count}" # 原有业务逻辑 mail(to: email, subject: "你的活动通知") # 确保此处一定会执行,没有条件跳过 Rails.logger.info "[CampaignMailer] 邮件对象生成成功" rescue => e Rails.logger.error "[CampaignMailer] 执行失败: #{e.class} - #{e.message}\n#{e.backtrace&.join("\n")}" raise e # 抛出异常让Sidekiq默认重试逻辑生效,方便复现问题 end end end
- 检查Sidekiq全局异常处理配置,确认没有对
ActiveRecord::RecordNotFound、ActionMailer::Base::NullMail这类异常做静默丢弃处理。 - 临时关闭该类邮件任务的sidekiq-unique-jobs锁配置,重新发送测试是否还出现丢信情况,排查锁逻辑的影响。
- 检查全局邮件拦截器/过滤器配置,确认没有对特定收件人/域名做静默拦截。
内容的提问来源于stack exchange,提问作者daveharris
相关产品推荐
相关产品推荐

