如何从Solid Queue中删除指定的定时任务?
解决Solid Queue中重复生日提醒定时任务的问题
核心思路
更新亲友生日时,先清理对应未执行的旧定时任务,再创建新的任务,避免重复投递邮件。
具体实现方案
方案1:记录任务ID到关联模型(推荐)
在亲友模型中新增reminder_job_id字段,存储对应定时任务的ID,更新时直接通过ID定位删除旧任务:
- 生成迁移添加字段:
rails generate migration AddReminderJobIdToRelatives reminder_job_id:string rails db:migrate
- 创建任务时记录ID:
# 亲友模型的创建/更新回调中 def schedule_birthday_reminder # 删除旧任务(如果存在) if reminder_job_id.present? SolidQueue::Job.find_by(id: reminder_job_id)&.destroy end # 计算用户时区下的生日午夜时间 reminder_time = user.timezone.local_to_utc(Date.today.change(month: birthdate.month, day: birthdate.day).beginning_of_day) # 调度新任务并记录ID job = BirthdayReminderJob.set(wait_until: reminder_time).perform_later(user, self) update(reminder_job_id: job.job_id) end
- 在亲友模型中设置回调触发:
class Relative < ApplicationRecord belongs_to :user after_save :schedule_birthday_reminder, if: :birthdate_changed? end
方案2:通过任务参数查询删除
如果不想新增字段,可以通过Solid Queue的任务参数查询定位对应任务,适合数据库支持JSON查询的场景(如PostgreSQL):
def schedule_birthday_reminder # 查询并删除未执行的旧任务 old_jobs = SolidQueue::Job.where(queue_name: 'default') # 替换为你的队列名 .where("arguments ->> 'relative_id' = ?", id.to_s) .where("arguments ->> 'user_id' = ?", user.id.to_s) .where(status: [:pending, :scheduled]) # 只清理未执行的任务 old_jobs.destroy_all # 创建新任务 reminder_time = user.timezone.local_to_utc(Date.today.change(month: birthdate.month, day: birthdate.day).beginning_of_day) BirthdayReminderJob.set(wait_until: reminder_time).perform_later(user, self) end
注意:如果是MySQL,JSON查询语法略有不同,可使用
JSON_EXTRACT(arguments, '$.relative_id') = ?替代。
额外注意事项
- 确保只删除未执行的任务(
pending或scheduled状态),已执行的任务无需处理。 - 如果生日是每年重复提醒,需要考虑每年重新调度任务的逻辑(比如每年年初重新生成下一年的任务),避免任务过期后无法触发。
内容的提问来源于stack exchange,提问作者Juzer Shakir
相关产品推荐
相关产品推荐

