如何在Docker容器中更新Laravel队列Worker的运行代码
我在Docker容器中运行了一个Laravel实例,用supervisord维护20个队列Worker。Dockerfile的启动命令是:
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]
其中supervisord引入了laravel-worker.conf,配置如下:
[program:laravel-worker] directory=/var/www process_name=%(program_name)s_%(process_num)02d command=php artisan queue:work --sleep=3 --tries=3 --timeout=950 autostart=true autorestart=true stopasgroup=true killasgroup=true user=www-data numprocs=20 redirect_stderr=true stdout_logfile=/var/www/logs/queue-worker-error.log stdout_logfile_maxbytes=524288 stderr_logfile=/var/www/logs/queue-worker-error.log stderr_logfile_maxbytes=524288 stopwaitsecs=3600 priority=6
另外还有一个supervisord配置的bash脚本,用于定时任务:
while true do php /var/www/artisan schedule:run --no-interaction & sleep 60 done
现在遇到的问题是:更新PHP代码后,队列任务依然在尝试用旧代码执行。我已经试过以下操作但都无效:
- 执行
php artisan queue:restart重启Worker - 执行
php artisan queue:flush清空队列 - 用
docker restart <container>重启容器 - 删除容器和镜像后重新构建
想问问还有什么可以尝试的解决方法?
我来帮你梳理几个可能的排查点和解决办法——毕竟Laravel队列+Supervisord+Docker的组合,偶尔会因为进程管理或代码同步的细节掉坑:
强制杀掉所有Worker进程,让Supervisord重新拉起新进程
php artisan queue:restart是让Worker在完成当前任务后退出,但你设置的stopwaitsecs=3600(1小时)意味着Supervisord会等1小时才强制杀掉没退出的Worker。如果有Worker卡在超时任务上,就会一直跑旧代码。你可以手动进入容器杀掉所有队列进程:docker exec -it <container-id> bash pkill -f "php artisan queue:work"之后Supervisord会根据
autorestart=true自动重启新的Worker,这些新进程会加载最新代码。清理延迟/重试队列的残留任务
queue:flush只会清空默认队列的待处理任务,但失败的任务可能被放到了延迟队列(比如Redis的queues:default:delayed)或预留队列(queues:default:reserved)里,这些任务不会被flush清理。- 如果用Redis队列,执行:
# 进入容器的Redis客户端 docker exec -it <container-id> redis-cli # 查看所有队列相关键 KEYS "queues:*" # 删除延迟和预留队列 DEL queues:default:delayed queues:default:reserved - 如果用数据库队列,直接操作
jobs和failed_jobs表,删除所有未完成的任务。
- 如果用Redis队列,执行:
确认代码是否真的同步到容器中
Docker的构建缓存可能导致新代码没被复制到镜像里,即使你删了容器。构建镜像时加上--no-cache强制重新构建:docker build --no-cache -t your-laravel-image .另外,如果你用了本地卷挂载到容器,要确认本地代码确实是最新的,且挂载没有覆盖容器内的代码。可以进入容器检查代码文件的修改时间:
docker exec -it <container-id> ls -l /var/www/app/Http/Controllers/YourUpdatedFile.php清理Laravel的缓存文件
有时候旧的配置、路由或视图缓存会导致代码逻辑没有更新,尤其是你开启了缓存的话。进入容器执行:php artisan config:clear php artisan route:clear php artisan view:clear php artisan cache:clear检查Worker的运行权限
你的Worker用www-data用户运行,要确认这个用户有权限读取最新的代码文件。如果更新代码后文件权限变成了root,www-data可能无法读取新文件,导致Worker继续使用旧的缓存代码。可以修复权限:docker exec -it <container-id> chown -R www-data:www-data /var/www调整Supervisord的Worker配置细节
你当前的timeout=950设置过长,可能导致Worker长时间卡在旧任务上,建议缩短到合理范围(比如120秒);另外如果你的任务不是发到默认队列,也可以在命令中显式指定队列:command=php artisan queue:work default --sleep=3 --tries=3 --timeout=120
内容的提问来源于stack exchange,提问作者murume

