Heroku生产环境Sidekiq Worker无法正常触发执行问题排查
问题描述
我在Rails 6应用中配置了ActiveRecord回调(after_create),预期在ProductsBatch记录每次创建时调用SyncProductsWorker(Sidekiq Worker)。该功能本地运行完全正常,但部署到Heroku生产环境后Worker始终不执行,哪怕在Heroku Rails控制台手动触发Worker、拿到了合法任务ID,日志里也没有对应执行记录,只有default队列的任务能正常运行。
相关代码
配置了after_create回调的ProductsBatch模型
module Imports class ProductsBatch < ImportsRecord attr_accessor :product_codes after_create :enqueue def enqueue ::Imports::SyncProductsWorker.perform_async(product_codes, self.id) end end end # 上述模型的基类 class ImportsRecord < ApplicationRecord self.abstract_class = true connects_to database: { writing: :imports } end
SyncProductsWorker实现
module Imports class SyncProductsWorker include Sidekiq::Worker sidekiq_options queue: 'imports_sync' def perform(list, id) # 业务处理逻辑 end end end
Sidekiq配置
config/sidekiq.yml:
:max_retries: 16 :queues: - default - imports_sync - imports_fetch_all :dynamic: true
config/initializers/sidekiq.rb:
redis = { url: ENV['REDIS_URL'], ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE } } Sidekiq.configure_server do |config| config.redis = redis end Sidekiq.configure_client do |config| config.redis = redis end
异常复现记录
Heroku Rails控制台手动调用Worker返回了任务ID:
heroku run rails console --app test-app › Warning: heroku update available from 7.47.7 to 7.60.2. Running rails console on ⬢ test-app... up, run.8489 (Hobby) Loading production environment (Rails 6.1.4.1) irb(main):013:0> ::Imports::SyncProductsWorker.perform_async(['11'], 10) => "5edf93e27fa2f41245587d49"
但Heroku日志中无该任务的任何执行记录,仅能看到default队列的任务日志:
2022-06-06T22:02:00.240650+00:00 app[worker.1]: [ActiveJob] [ProductAvailabilityAdjusterJob] [25c15f9d-e032-438e-bda2-16ffd557cc32] Performed ProductAvailabilityAdjusterJob (Job ID: 25c15f9d-e032-438e-bda2-16ffd557cc32) from Sidekiq(default) in 5.44ms 2022-06-06T22:02:00.240789+00:00 app[worker.1]: pid=4 tid=2xbk class=ProductAvailabilityAdjusterJob jid=91ad7e69e061df9f2f681ef3 elapsed=0.006 INFO: done
解决方案
核心原因是Heroku上启动的Sidekiq进程没有加载自定义队列配置,默认只监听default队列,投递到imports_sync队列的任务已经成功写入Redis,但没有进程消费,按以下步骤修复:
- 修正Procfile中的Sidekiq启动命令,必须显式通过
-C参数指定配置文件路径,否则生产环境Sidekiq不会自动读取config/sidekiq.yml。把worker启动行改为:
这是该场景下最高发的踩坑点:本地开发环境Rails会自动加载配置目录下的sidekiq.yml,但Heroku生产环境不会自动加载该文件,必须显式指定。worker: bundle exec sidekiq -C config/sidekiq.yml - 重新部署后检查Sidekiq启动日志,确认启动日志里打印的监听队列列表包含
imports_sync、imports_fetch_all,再测试任务执行即可。 - 如果改完启动命令仍有问题,依次排查两点:
- 执行
heroku ps --app 你的应用名确认worker dyno处于正常启动状态,Heroku默认不会自动开启worker dyno,很多人部署完只启动了web进程 - 确认web dyno和worker dyno的
REDIS_URL环境变量值完全一致,避免客户端写入Redis、服务端连另一个Redis实例的情况
- 执行
内容的提问来源于stack exchange,提问作者mr_muscle
相关产品推荐
相关产品推荐

