available = $c instanceof CoroutineInterface; if (!$this->available) { logger()->error('排程任务只能在协程环境下使用'); } } /** * 添加一个排程任务 * * @param Cron $cron Cron 注解 */ public function addSchedule(Cron $cron): void { if (!$this->available) { return; } $next_run = $cron->expression->getNextRunDate()->getTimestamp(); // 防止在同一分钟内重复执行 if ($next_run < $this->next_run) { $next_run = $this->next_run; } $this->next_run = $cron->expression->getNextRunDate()->getTimestamp(); $wait_ms = max(0, ($next_run - time()) * 1000); Timer::after($wait_ms, function () use ($cron) { $this->dispatch($cron); $this->addSchedule($cron); }); } public function dispatch(Cron $cron): void { // 检查是否重叠执行 if ($cron->no_overlap && in_array($cron, $this->executing, true)) { return; } $this->executing[] = $cron; // 新建一个协程运行排程任务,避免阻塞 Adaptive::getCoroutine()->create(function () use ($cron) { $callable = $cron->class === '' ? $cron->method : [$cron->class, $cron->method]; container()->call($callable); $this->executing = array_diff($this->executing, [$cron]); }); } }