Hyperf中跳过节假日定时任务需在任务执行前判断当日是否为法定节假日且非调休上班日,推荐使用chinese-holidays等开源数据源预加载,封装HolidayChecker服务支持缓存与周末配置,并在@Cron任务handle()中校验后return跳过。

<p>Hyperf 中跳过节假日定时任务,核心是拦截任务执行前的判断逻辑,在任务真正触发前检查当天是否为法定节假日。官方不直接提供节假日判断能力,需结合外部节假日数据(如国家发布的放假安排)自行实现。</p>
<H3>获取节假日数据源</H3>
<p>推荐使用稳定、更新及时的开源节假日 API 或本地 JSON 数据:</p>
<ul>
<li>GitHub 上维护的 <strong>chinese-holidays</strong> 项目(如 <code>shufo/chinese-holidays</code>),含历年调休、工作日/休息日标记</li>
<li>自建轻量级节假日表(MySQL/Redis),字段建议:date(Y-m-d)、is_official_holiday(bool)、is_workday_adjusted(bool,调休上班日)</li>
<li>避免实时调用第三方 HTTP 接口(影响任务稳定性),建议启动时预加载或每日凌晨定时同步一次</li>
</ul>
<H3>在定时任务中注入假期判断逻辑</H3>
<p>以 <code>@Cron</code> 注解任务为例,在 <code>handle()</code> 开头加入校验:</p>
<pre><code>#[Cron("0 0 * * *")]
public function dailyJob(): void
{
$today = date('Y-m-d');
if ($this->holidayChecker->isHoliday($today)) {
\Hyperf\Logger\LoggerFactory::get('cron')->info("Skip dailyJob on holiday: {$today}");
return;
}
// 正常执行业务逻辑...
}</code></pre>
<p>其中 <code>isHoliday()</code> 应同时满足:<strong>是法定节假日</strong> 且 <strong>非调休上班日</strong>(即:true && !is_workday_adjusted)</p>
<H3>封装可复用的 HolidayChecker 服务</H3>
<p>创建 <code>HolidayChecker</code> 类,统一管理判断规则:</p>
<ul>
<li>支持缓存(如 Redis 缓存当日结果,避免重复计算)</li>
<li>兼容「周末自动跳过」需求(可配置 <code>$skipWeekends = true</code>)</li>
<li>提供 <code>isWorkday(string $date): bool</code> 方法,返回「是否应执行任务的工作日」</li>
<li>示例逻辑:<code>return !$this->isHoliday($date) && (!$this->skipWeekends || !in_array(date('w', strtotime($date)), [0, 6]))</code></li>
</ul>
<H3>注意进程与定时器生命周期</H3>
<p>Hyperf 的 <code>Crontab</code> 是基于 <code>Server</code> 进程内定时器实现的,不是独立进程:</p>
<ul>
<li>所有 <code>@Cron</code> 任务共享同一个协程调度器,跳过执行不会影响其他任务</li>
<li>无需手动 stop/start 进程,只需在业务逻辑中 return 即可优雅跳过</li>
<li>若使用 <code>crontab:reload</code> 命令热更任务,需确保节假日数据也同步刷新(建议监听 reload 事件重载缓存)</li>
</ul>