Symfony Scheduler需显式注册命令、正确配置cron表达式、重定向日志输出并用systemd等守护进程管理调度器运行。

symfony/console 命令如何被 Scheduler 正确识别
Symfony Scheduler 不会自动扫描所有 Command 类,它只加载显式注册进调度器的命令。如果你写了一个继承 Command 的类,但没在 scheduler.yaml 或 PHP 配置里声明,它根本不会出现在调度列表里,也不会报错——只是静默忽略。
- 必须在
config/packages/scheduler.yaml中用tasks显式定义,例如:tasks: send_daily_report: command: 'app:send-daily-report' schedule: '0 9 * * *' -
command值必须和configure()中设置的命令名完全一致(包括空格、连字符),大小写敏感 - 命令类需已注册为服务(默认启用 autoconfigure/autoconfigure 时通常满足,但若手动禁用了,要加
tags: ['console.command'])
schedule 表达式写错导致任务永不触发
常见的 schedule 字段值不是 cron 表达式就无效,而 Symfony 默认用的是标准 Unix cron 格式(5 字段),不支持 @daily 这类别名,也不接受秒字段(6 字段)——哪怕你从其他文档复制过来,也可能直接失效。
- 正确写法:
'0 2 * * *'(每天凌晨 2 点),'*/5 * * * *'(每 5 分钟) - 错误写法:
'@hourly'(不识别)、'0 */2 * * * *'(多了一个秒字段,解析失败) - 开发时可用
php bin/console scheduler:debug查看实际解析出的下次执行时间;如果显示never,基本就是表达式语法问题
任务执行失败但日志里看不到错误
Symfony Scheduler 默认把命令执行的 stdout/stderr 丢弃了,除非你主动配置输出重定向或启用 debug 日志。这意味着命令抛异常、权限不足、环境变量缺失,都可能“看起来没运行”,实则失败后静默退出。
- 临时排查:在
tasks配置中加output: '%kernel.logs_dir%/scheduler.log',把输出追加进去 - 更可靠的方式是让命令自身处理异常并记录,比如在
execute()里 try/catch 后写入$this->logger - 注意:Scheduler 进程本身不读取
.env,确保APP_ENV和数据库连接等关键配置已在 Web/CLI 环境中预设好,否则命令可能因环境缺失而提前崩溃
生产环境调度器进程没跑起来
Scheduler 不是守护进程,它本身不长期运行;你得靠外部进程管理器(如 systemd、supervisord)持续拉起 php bin/console scheduler:run。漏掉这步,任务就永远不执行——本地开发用 php bin/console scheduler:run --verbose 手动跑一次没问题,但上线后必须有常驻机制。
- systemd 示例:写一个 service 文件,
ExecStart=/usr/bin/php /var/www/app/bin/console scheduler:run --env=prod,并设Restart=always - 别用
nohup+&启动,缺少进程生命周期管理,容易僵死或重复启动 - 多个服务器部署时,注意避免同一任务被多台机器同时执行;要么用分布式锁(如 Redis),要么只在单点运行调度器进程
真正麻烦的不是写任务,而是让调度器稳定地“活”在生产环境里,并且每次失败都有迹可循。环境差异、权限、日志路径、进程存活——这些地方一松懈,任务就变成黑盒。










