Dokku部署后未完成任务的Worker被移除问题求助
解决Dokku部署Rails应用时Worker任务中断问题
方案一:让旧Worker完成任务后再终止(优雅关闭)
- 配置Worker框架的优雅关闭超时:如果使用Sidekiq这类主流Worker框架,在
config/initializers/sidekiq.rb中添加超时配置,让Worker收到终止信号后,先处理完当前任务再退出:
自定义Worker需自行实现信号捕获逻辑:捕获Sidekiq.configure_server do |config| config.shutdown_timeout = 300 # 等待5分钟,可根据任务实际时长调整 endTERM信号后,停止接收新任务,待当前所有任务执行完毕再退出进程。 - 调整Dokku的进程停止超时:通过Dokku配置给旧Worker足够的处理时间,避免被强制杀掉:
dokku config:set YOUR_APP_NAME DOKKU_PROCESS_STOP_TIMEOUT=300
方案二:让新Worker承接未完成任务(任务持久化+幂等性)
- 确保任务持久化到外部存储:不要将任务存在Worker实例本地,使用Redis、数据库等外部存储(比如Sidekiq默认用Redis),部署后新Worker连接同一存储即可获取未完成任务。
- 实现任务幂等性:即使任务被重复执行也不会产生异常结果。可以给每个任务添加唯一标识,执行前检查任务是否已处理:
class MyWorker include Sidekiq::Worker sidekiq_options unique: :until_executed def perform(task_id) return if Task.find(task_id).completed? # 执行任务逻辑 Task.find(task_id).update!(completed: true) end end - 开启任务重试机制:在Worker配置中启用重试,中断的任务会自动重新入队,由新Worker接手处理:
class MyWorker include Sidekiq::Worker sidekiq_options retry: 3 # 重试3次,可按需调整 end
方案三:调整Dokku部署策略
- 使用滚动部署:让Dokku先启动新Worker,再逐步关闭旧Worker,保证任务处理不中断:
dokku apps:set YOUR_APP_NAME DOKKU_DEPLOY_STRATEGY=rollout - 控制滚动部署的批次大小:如果有多个Worker实例,设置每次只替换一个实例,减少对任务队列的影响:
dokku apps:set YOUR_APP_NAME DOKKU_ROLLOUT_BATCH_SIZE=1
内容的提问来源于stack exchange,提问作者Pimenta
相关产品推荐
相关产品推荐

