Ruby on Rails中如何将Sidekiq短信任务入队并仅手动执行?
解决Sidekiq任务手动触发执行的方案
下面给你几个实用的方案,让短信任务留在队列里,等你手动触发才执行:
方法一:用专属“待执行”队列,按需启动消费者
这是最直接的处理方式:
- 入队时指定一个专门的队列(比如
sms_pending),不要用默认队列:Worker.set(queue: 'sms_pending').perform_async(:send_sms, phone_number, content) - 平时启动Sidekiq时,只监听业务正常运行的队列(比如
default),启动命令如下:
这样bundle exec sidekiq -q defaultsms_pending队列里的任务会一直处于待执行状态,不会被自动处理。 - 需要手动执行时,二选一操作:
- 临时启动一个仅监听
sms_pending队列的Sidekiq进程:
任务处理完成后关闭该进程即可;bundle exec sidekiq -q sms_pending - 通过Sidekiq Web UI的「Move Jobs」功能,把
sms_pending队列里的任务批量移动到default队列,让正在运行的Sidekiq进程自动处理。
- 临时启动一个仅监听
方法二:把任务设为远期定时任务,手动提前触发
利用Sidekiq的预定任务机制实现延迟触发:
- 入队时把执行时间设为很远的未来(比如1年后),任务会进入「Scheduled」列表,不会立即执行:
# 入队一个1年后才执行的任务 Worker.perform_in(1.year, :send_sms, phone_number, content) - 需要执行时,通过Sidekiq Web UI找到该预定任务,点击「Enqueue Now」,任务就会立即进入执行队列;
- 如果需要批量操作,也可以用Sidekiq API手动处理:
# 入队时记录任务jid job_jid = Worker.perform_in(1.year, :send_sms, phone_number, content) # 手动触发时,删除预定任务并立即入队执行 if scheduled_job = Sidekiq::ScheduledSet.new.find_job(job_jid) scheduled_job.delete Worker.perform_async(:send_sms, phone_number, content) end
方法三:在Worker里加执行开关(适合复杂场景)
如果需要更灵活的状态控制,可以给任务添加“待执行”标记:
- 入队时传递
pending: true参数:Worker.perform_async(:send_sms, phone_number, content, pending: true) - 修改Worker逻辑,检查标记,未触发就重新入队(注意关闭自动重试,避免无限循环):
class Worker include Sidekiq::Worker sidekiq_options retry: false # 关闭自动重试 def perform(method_name, *args) # 取出最后一个参数里的pending标记 opts = args.last.is_a?(Hash) ? args.pop : {} if opts[:pending] # 重新入队,保持任务在队列中 self.class.perform_async(method_name, *args, pending: true) return end # 标记为允许执行时,调用服务发送短信 Services.send(method_name, *args) end end - 需要触发时,通过Sidekiq Web UI编辑任务参数,把
pending: true改成pending: false,任务下次被消费时就会执行。
内容的提问来源于stack exchange,提问作者Merouane Amqor
相关产品推荐
相关产品推荐

