@Crontab注解不生效的主因是Swoole未启用定时器支持,需检查php --ri swoole中support timer是否为enabled,否则需重编译Swoole并启用--enable-timerc;同时确保类在App\Task命名空间、方法名为execute且无参数,rule格式须符合标准五段crontab语法(不支持@daily等符号名)。

为什么@Crontab注解不生效?先确认Swoole进程是否启用了定时器
Hyperf的@Crontab注解本质依赖Swoole的tick或after定时机制,不是Linux crond。如果php bin/hyperf.php start启动后任务完全没执行,大概率是Swoole未启用定时器支持——这在Docker或某些精简PHP环境中容易被忽略。
检查方式:php --ri swoole输出中必须包含support timer: enabled。若为disabled,需重新编译Swoole并启用--enable-timerc(非--enable-timer)选项。
- Hyperf 3.x 要求 Swoole ≥ 5.0.1,且默认启用定时器;2.x 对Swoole 4.8+有兼容性问题,建议升到4.8.13+
- 注解扫描只在
App\Task命名空间下生效(默认配置),把类放在App\Controller里不会被识别 - CLI模式下运行
php bin/hyperf.php cron:list可查看已注册任务,空列表说明注解未被扫描到
@Crontab参数怎么填才符合crontab语法?别直接抄Linux表达式
Hyperf的@Crontab接受两种时间格式:rule(标准五段crontab)和interval(毫秒)。但注意:它**不支持**@daily、@hourly这类符号名,也不支持*/5 * * * *中的*前缀写法(如*/5会被解析失败)。
正确写法示例:
#[Crontab(rule: '0 0 * * *')] // 每天0点0分执行(注意:分钟在前,小时在后) #[Crontab(interval: 60000)] // 每60秒执行一次 #[Crontab(rule: '0 30 9-17 * * 1-5')] // 工作日9:30–17:30每小时一次(注意周字段是1-5,非0-4)
- 月份和星期字段支持英文缩写(
jan,mon),但大小写敏感,推荐用数字更稳 -
rule和interval不能同时设,否则后者会覆盖前者 - 秒级精度不支持,最小单位是分钟(
rule)或毫秒(interval),但高频任务慎用interval,可能堆积协程
任务类必须继承Task还是实现特定接口?其实都不用
Hyperf对@Crontab任务类唯一硬性要求是:类中必须有一个execute()方法,且该方法无参数、返回void或mixed(返回值会被忽略)。不需要继承Task基类,也不需要实现任何接口。
常见错误写法:
#[Crontab(rule: '0 * * * *')]
class ReportTask
{
public function execute($param) { ... } // ❌ 多了参数
}
<h1>[Crontab(rule: '0 <em> </em> <em> </em>')]</h1><p>class ReportTask
{
public function handle() { ... } // ❌ 方法名必须是execute
}-
execute()方法内可直接使用$this->container获取容器实例,无需手动注入 - 若需DI依赖,用
#[Inject]标注属性即可,Hyperf会在调用前自动注入 - 避免在
execute()里做阻塞IO(如sleep()、同步Redis调用),应改用co::sleep()或协程客户端
多个@Crontab任务共享同一个类时,如何区分执行逻辑?靠方法名+注解绑定
一个类可以定义多个@Crontab,只要每个注解绑定到不同方法上。Hyperf通过「类+方法名」组合唯一标识任务,不是靠类本身。
例如:
class DailyTask
{
#[Crontab(rule: '0 0 * * *')]
public function cleanLogs()
{
// 清理日志
}
<pre class="brush:php;toolbar:false;">#[Crontab(rule: '0 30 2 * * *')]
public function backupDB()
{
// 备份数据库
}}
- 两个任务共用
DailyTask类,但互不影响,容器会分别实例化并调用对应方法 - 方法名不能重复,否则后注册的会覆盖前一个(
php bin/hyperf.php cron:list可验证) - 如果想复用部分逻辑,可提取私有方法,但不要给私有方法加
@Crontab,否则会被误注册
Hyperf的@Crontab轻量但边界清晰:它不处理任务失败重试、分布式锁、执行历史记录——这些得靠你自己集成hyperf/task、Redis锁或自定义调度器。别指望一个注解解决所有调度问题。


















