267 lines
108 KiB
JavaScript
267 lines
108 KiB
JavaScript
import{_ as i,o as a,c as n,a2 as t}from"./chunks/framework.B-QBKwc1.js";const o=JSON.parse('{"title":"定时任务","description":"定时任务系统由三部分组成:JobService(调度逻辑)+ BaseTask(任务处理器)+ Artisan 命令(job:run / job:daemon 命令行入口)。","frontmatter":{},"headers":[],"relativePath":"zh/modules/job.md","filePath":"zh/modules/job.md"}'),h={name:"zh/modules/job.md"};function l(p,s,k,e,d,r){return a(),n("div",null,[...s[0]||(s[0]=[t(`<h1 id="_6-11-定时任务" tabindex="-1">6.11 定时任务 <a class="header-anchor" href="#_6-11-定时任务" aria-label="Permalink to "6.11 定时任务""></a></h1><div class="tip custom-block"><p class="custom-block-title">概述</p><p>定时任务系统由三部分组成:<code>JobService</code>(调度逻辑)+ <code>BaseTask</code>(任务处理器)+ Artisan 命令(<code>job:run</code> / <code>job:daemon</code> 命令行入口)。支持三种触发方式:Linux Crontab、Windows 计划任务、Daemon 守护进程。</p></div><h2 id="系统架构" tabindex="-1">系统架构 <a class="header-anchor" href="#系统架构" aria-label="Permalink to "系统架构""></a></h2><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>┌─────────────────────────────────────────────────────────────────┐</span></span>
|
||
<span class="line"><span>│ 触发层(三选一) │</span></span>
|
||
<span class="line"><span>│ │</span></span>
|
||
<span class="line"><span>│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │</span></span>
|
||
<span class="line"><span>│ │ Linux Crontab│ │Windows 计划 │ │ Daemon 守护 │ │</span></span>
|
||
<span class="line"><span>│ │ │ │任务 │ │ 进程 │ │</span></span>
|
||
<span class="line"><span>│ │ * * * * * │ │ schtasks │ │ php artisan │ │</span></span>
|
||
<span class="line"><span>│ │ php artisan │ │ │ │ job:daemon │ │</span></span>
|
||
<span class="line"><span>│ │ job:run │ │ │ │ │ │</span></span>
|
||
<span class="line"><span>│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │</span></span>
|
||
<span class="line"><span>│ │ │ │ │</span></span>
|
||
<span class="line"><span>│ └─────────────────┼─────────────────┘ │</span></span>
|
||
<span class="line"><span>│ │ │</span></span>
|
||
<span class="line"><span>│ ▼ │</span></span>
|
||
<span class="line"><span>│ ┌─────────────────────────────┐ │</span></span>
|
||
<span class="line"><span>│ │ JobRunCommand / JobDaemon │ │</span></span>
|
||
<span class="line"><span>│ │ php artisan job:run │ │</span></span>
|
||
<span class="line"><span>│ │ php artisan job:daemon │ │</span></span>
|
||
<span class="line"><span>│ └────────────┬────────────────┘ │</span></span>
|
||
<span class="line"><span>└───────────────────────────┼─────────────────────────────────────┘</span></span>
|
||
<span class="line"><span> │</span></span>
|
||
<span class="line"><span> ▼</span></span>
|
||
<span class="line"><span>┌─────────────────────────────────────────────────────────────────┐</span></span>
|
||
<span class="line"><span>│ 调度层(JobService) │</span></span>
|
||
<span class="line"><span>│ │</span></span>
|
||
<span class="line"><span>│ runPending() shouldRun() │</span></span>
|
||
<span class="line"><span>│ ├─ 查询 status=1 的任务 ├─ 解析 cron 表达式 │</span></span>
|
||
<span class="line"><span>│ ├─ 逐个判断是否到执行时间 ├─ 分 时 日 月 周 逐段匹配 │</span></span>
|
||
<span class="line"><span>│ └─ 到期则执行 └─ 全部匹配返回 true │</span></span>
|
||
<span class="line"><span>│ │</span></span>
|
||
<span class="line"><span>│ executeJob($job) │</span></span>
|
||
<span class="line"><span>│ ├─ 检查执行策略(立即/排队/放弃) │</span></span>
|
||
<span class="line"><span>│ ├─ 调用 doExecute() 实际执行 │</span></span>
|
||
<span class="line"><span>│ ├─ 记录 JobLog 执行日志 │</span></span>
|
||
<span class="line"><span>│ └─ 返回执行结果 │</span></span>
|
||
<span class="line"><span>└───────────────────────────┼─────────────────────────────────────┘</span></span>
|
||
<span class="line"><span> │</span></span>
|
||
<span class="line"><span> ▼</span></span>
|
||
<span class="line"><span>┌─────────────────────────────────────────────────────────────────┐</span></span>
|
||
<span class="line"><span>│ 执行层 │</span></span>
|
||
<span class="line"><span>│ │</span></span>
|
||
<span class="line"><span>│ doExecute($job) │</span></span>
|
||
<span class="line"><span>│ ├─ 判断任务类型 │</span></span>
|
||
<span class="line"><span>│ │ │</span></span>
|
||
<span class="line"><span>│ ├─ http:// / https:// → executeHttp() │</span></span>
|
||
<span class="line"><span>│ │ └─ curl 发起 HTTP 请求 │</span></span>
|
||
<span class="line"><span>│ │ │</span></span>
|
||
<span class="line"><span>│ └─ 其它 → executeInternal() │</span></span>
|
||
<span class="line"><span>│ └─ 映射到 App\\Task\\{Name}Task::run() │</span></span>
|
||
<span class="line"><span>│ │</span></span>
|
||
<span class="line"><span>│ 示例: │</span></span>
|
||
<span class="line"><span>│ url = "SendSms" → App\\Task\\SendSmsTask::run() │</span></span>
|
||
<span class="line"><span>│ url = "Order/Close" → App\\Task\\Order\\CloseTask::run() │</span></span>
|
||
<span class="line"><span>│ url = "https://..." → HTTP 请求 │</span></span>
|
||
<span class="line"><span>└─────────────────────────────────────────────────────────────────┘</span></span></code></pre></div><h2 id="任务数据结构" tabindex="-1">任务数据结构 <a class="header-anchor" href="#任务数据结构" aria-label="Permalink to "任务数据结构""></a></h2><h3 id="job-表字段" tabindex="-1">job 表字段 <a class="header-anchor" href="#job-表字段" aria-label="Permalink to "job 表字段""></a></h3><table tabindex="0"><thead><tr><th>字段</th><th>类型</th><th>说明</th></tr></thead><tbody><tr><td><code>job_name</code></td><td>varchar</td><td>任务名称</td></tr><tr><td><code>job_alias</code></td><td>varchar</td><td>任务别名(唯一)</td></tr><tr><td><code>job_group</code></td><td>varchar</td><td>任务分组</td></tr><tr><td><code>status</code></td><td>tinyint</td><td>状态:0=未发布 1=运行中 2=暂停</td></tr><tr><td><code>cron_expression</code></td><td>varchar</td><td>Cron 表达式(5段:分 时 日 月 周)</td></tr><tr><td><code>execute_policy</code></td><td>tinyint</td><td>执行策略:1=立即 2=执行一次 3=放弃</td></tr><tr><td><code>is_sync</code></td><td>tinyint</td><td>是否同步:0=否 1=是</td></tr><tr><td><code>url</code></td><td>varchar</td><td>任务地址(内部类名或外部URL)</td></tr><tr><td><code>params</code></td><td>text</td><td>任务参数(JSON)</td></tr><tr><td><code>note</code></td><td>text</td><td>备注</td></tr></tbody></table><h3 id="job-log-表字段" tabindex="-1">job_log 表字段 <a class="header-anchor" href="#job-log-表字段" aria-label="Permalink to "job_log 表字段""></a></h3><table tabindex="0"><thead><tr><th>字段</th><th>类型</th><th>说明</th></tr></thead><tbody><tr><td><code>job_id</code></td><td>int</td><td>关联任务ID</td></tr><tr><td><code>job_name</code></td><td>varchar</td><td>任务名称</td></tr><tr><td><code>job_group</code></td><td>varchar</td><td>任务分组</td></tr><tr><td><code>job_message</code></td><td>text</td><td>执行结果消息(截取前500字符)</td></tr><tr><td><code>cron_expression</code></td><td>varchar</td><td>Cron 表达式</td></tr><tr><td><code>status</code></td><td>tinyint</td><td>状态:0=正常 1=失败</td></tr><tr><td><code>start_time</code></td><td>datetime</td><td>开始时间</td></tr><tr><td><code>end_time</code></td><td>datetime</td><td>结束时间</td></tr><tr><td><code>consume_time</code></td><td>int</td><td>耗时(毫秒)</td></tr><tr><td><code>exception_info</code></td><td>text</td><td>异常信息(截取前2000字符)</td></tr></tbody></table><h2 id="状态说明" tabindex="-1">状态说明 <a class="header-anchor" href="#状态说明" aria-label="Permalink to "状态说明""></a></h2><table tabindex="0"><thead><tr><th>状态值</th><th>说明</th><th>可执行</th><th>可暂停</th><th>可启动</th></tr></thead><tbody><tr><td>0</td><td>未发布</td><td>✗</td><td>✗</td><td>✓</td></tr><tr><td>1</td><td>运行中</td><td>✓</td><td>✓</td><td>✗</td></tr><tr><td>2</td><td>暂停</td><td>✗</td><td>✗</td><td>✓</td></tr><tr><td>3</td><td>已删除</td><td>✗</td><td>✗</td><td>✗</td></tr></tbody></table><h2 id="执行策略" tabindex="-1">执行策略 <a class="header-anchor" href="#执行策略" aria-label="Permalink to "执行策略""></a></h2><table tabindex="0"><thead><tr><th>策略值</th><th>说明</th><th>行为</th></tr></thead><tbody><tr><td>1</td><td>立即执行</td><td>丢弃之前的执行,立即运行</td></tr><tr><td>2</td><td>执行一次</td><td>等待上一次完成后执行</td></tr><tr><td>3</td><td>放弃执行</td><td>如果上一次还在运行则跳过</td></tr></tbody></table><h2 id="Cron-表达式语法" tabindex="-1">Cron 表达式语法 <a class="header-anchor" href="#Cron-表达式语法" aria-label="Permalink to "Cron 表达式语法""></a></h2><p>标准 5 段格式:<code>分 时 日 月 周</code></p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>┌────────── 分钟(0-59)</span></span>
|
||
<span class="line"><span>│ ┌──────── 小时(0-23)</span></span>
|
||
<span class="line"><span>│ │ ┌────── 日(1-31)</span></span>
|
||
<span class="line"><span>│ │ │ ┌──── 月(1-12)</span></span>
|
||
<span class="line"><span>│ │ │ │ ┌── 周(0-6,0=周日)</span></span>
|
||
<span class="line"><span>│ │ │ │ │</span></span>
|
||
<span class="line"><span>* * * * *</span></span></code></pre></div><table tabindex="0"><thead><tr><th>表达式</th><th>说明</th></tr></thead><tbody><tr><td><code>* * * * *</code></td><td>每分钟</td></tr><tr><td><code>0 * * * *</code></td><td>每小时整点</td></tr><tr><td><code>0 0 * * *</code></td><td>每天 0 点</td></tr><tr><td><code>0 2 * * *</code></td><td>每天凌晨 2 点</td></tr><tr><td><code>0 0 * * 1</code></td><td>每周一 0 点</td></tr><tr><td><code>0 0 1 * *</code></td><td>每月 1 号 0 点</td></tr><tr><td><code>*/5 * * * *</code></td><td>每 5 分钟</td></tr><tr><td><code>0 */2 * * *</code></td><td>每 2 小时</td></tr><tr><td><code>0 9-18 * * 1-5</code></td><td>工作日 9-18 点每小时</td></tr><tr><td><code>0 2 1,15 * *</code></td><td>每月 1 号和 15 号凌晨 2 点</td></tr></tbody></table><h2 id="方式一-Linux-Crontab-推荐-" tabindex="-1">方式一:Linux Crontab(推荐) <a class="header-anchor" href="#方式一-Linux-Crontab-推荐-" aria-label="Permalink to "方式一:Linux Crontab(推荐)""></a></h2><div class="tip custom-block"><p class="custom-block-title">适用场景</p><p>Linux / macOS 服务器,最常用的定时任务触发方式。系统级 cron 每分钟触发一次 Artisan 命令。</p></div><h3 id="配置步骤" tabindex="-1">配置步骤 <a class="header-anchor" href="#配置步骤" aria-label="Permalink to "配置步骤""></a></h3><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 1. 编辑 crontab</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">crontab</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> -e</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 2. 添加定时任务(每分钟执行一次,推荐)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">*</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> *</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> *</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> *</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> *</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;"> cd /www/RXThinkCMF_Laravel13_EleVue </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">&&</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> /usr/bin/php</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> artisan</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> job:run</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> >></span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> /dev/null</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> 2>&1</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 调试时改为写入日志文件</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">*</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> *</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> *</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> *</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> *</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;"> cd /www/RXThinkCMF_Laravel13_EleVue </span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">&&</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> /usr/bin/php</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> artisan</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> job:run</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> >></span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> /var/log/job.log</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> 2>&1</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 3. 保存后验证</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">crontab</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> -l</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 查看已配置的 cron</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">tail</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> -f</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> /var/log/syslog</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> |</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> grep</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> CRON</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 查看 cron 日志</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">cd</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> /www/RXThinkCMF_Laravel13_EleVue</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> &&</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> php</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> artisan</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> job:run</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 手动执行一次</span></span></code></pre></div><div class="warning custom-block"><p class="custom-block-title">路径注意</p><ul><li><code>cd</code> 必须切换到<strong>项目根目录</strong>,否则 Laravel 无法找到 <code>.env</code> 与配置</li><li><code>php</code> 建议使用绝对路径(如 <code>/usr/bin/php</code>),避免 cron 环境变量不同导致找不到 PHP</li><li><code>>> /dev/null 2>&1</code> 表示丢弃输出,调试时改为写入日志文件</li></ul></div><h3 id="Crontab-常用命令" tabindex="-1">Crontab 常用命令 <a class="header-anchor" href="#Crontab-常用命令" aria-label="Permalink to "Crontab 常用命令""></a></h3><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">crontab</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> -e</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 编辑当前用户的 cron</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">crontab</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> -l</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 列出当前用户的 cron</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">crontab</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> -r</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 删除当前用户的所有 cron(慎用)</span></span></code></pre></div><h2 id="方式二-Windows-计划任务" tabindex="-1">方式二:Windows 计划任务 <a class="header-anchor" href="#方式二-Windows-计划任务" aria-label="Permalink to "方式二:Windows 计划任务""></a></h2><div class="tip custom-block"><p class="custom-block-title">适用场景</p><p>Windows Server 或本地开发环境(Laragon),通过任务计划程序定时触发。</p></div><h3 id="方式-A-图形界面配置" tabindex="-1">方式 A:图形界面配置 <a class="header-anchor" href="#方式-A-图形界面配置" aria-label="Permalink to "方式 A:图形界面配置""></a></h3><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>1. Win + R → taskschd.msc → 回车(打开任务计划程序)</span></span>
|
||
<span class="line"><span>2. 右侧点击"创建基本任务"</span></span>
|
||
<span class="line"><span>3. 名称:定时任务</span></span>
|
||
<span class="line"><span>4. 触发器:每天,重复间隔 1 分钟,持续时间无限期</span></span>
|
||
<span class="line"><span>5. 操作:启动程序</span></span>
|
||
<span class="line"><span> 程序或脚本:D:\\laragon\\bin\\php\\php-8.3.x-Win32-vs16-x64\\php.exe</span></span>
|
||
<span class="line"><span> 添加参数:artisan job:run</span></span>
|
||
<span class="line"><span> 起始于:D:\\laragon\\www\\RXThinkCMF_Laravel13_EleVue</span></span>
|
||
<span class="line"><span>6. 勾选"不管用户是否登录都要运行" → 完成</span></span></code></pre></div><h3 id="方式-B-命令行配置-schtasks-" tabindex="-1">方式 B:命令行配置(schtasks) <a class="header-anchor" href="#方式-B-命令行配置-schtasks-" aria-label="Permalink to "方式 B:命令行配置(schtasks)""></a></h3><div class="language-powershell vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">powershell</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 创建每分钟执行的任务(含工作目录与日志重定向)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">schtasks </span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">/</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">create </span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">/</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">tn </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">RXThinkCMF_Job</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> /</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">tr </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">cmd /c cd /d D:\\laragon\\www\\RXThinkCMF_Laravel13_EleVue && D:\\laragon\\bin\\php\\php-8.3.x-Win32-vs16-x64\\php.exe artisan job:run >> storage\\job.log 2>&1</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> /</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">sc minute </span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">/</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">mo </span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;">1</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> /</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">f</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 查询 / 手动运行 / 删除</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">schtasks </span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">/</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">query </span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">/</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">tn </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">RXThinkCMF_Job</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">schtasks </span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">/</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">run </span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">/</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">tn </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">RXThinkCMF_Job</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">schtasks </span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">/</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">delete </span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">/</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">tn </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">RXThinkCMF_Job</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> /</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">f</span></span></code></pre></div><div class="warning custom-block"><p class="custom-block-title">Windows 常见问题</p><ol><li><strong>路径空格</strong>:路径含空格时必须用引号包裹</li><li><strong>PHP 路径</strong>:使用 <code>php.exe</code> 的完整路径(Laragon 多版本共存时尤其注意 8.3 的路径)</li><li><strong>工作目录</strong>:必须设置为项目根目录</li><li><strong>输出重定向</strong>:<code>>></code> 在 <code>cmd /c</code> 内生效,注意相对路径基于工作目录</li></ol></div><h2 id="方式三-Daemon-守护进程" tabindex="-1">方式三:Daemon 守护进程 <a class="header-anchor" href="#方式三-Daemon-守护进程" aria-label="Permalink to "方式三:Daemon 守护进程""></a></h2><div class="tip custom-block"><p class="custom-block-title">适用场景</p><p>需要更精确的执行时机,或不想依赖系统 cron 的场景。进程常驻内存,自行调度。</p></div><h3 id="原理" tabindex="-1">原理 <a class="header-anchor" href="#原理" aria-label="Permalink to "原理""></a></h3><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>Daemon 进程启动</span></span>
|
||
<span class="line"><span> │</span></span>
|
||
<span class="line"><span> ▼</span></span>
|
||
<span class="line"><span>┌─────────────────────┐</span></span>
|
||
<span class="line"><span>│ while (true) │ 无限循环</span></span>
|
||
<span class="line"><span>│ │ │</span></span>
|
||
<span class="line"><span>│ ├─ runPending() │ 扫描并执行到期任务</span></span>
|
||
<span class="line"><span>│ ├─ sleep(60) │ 休眠 60 秒</span></span>
|
||
<span class="line"><span>│ └─ 继续循环 │</span></span>
|
||
<span class="line"><span>└─────────────────────┘</span></span></code></pre></div><ul><li>锁文件:<code>storage/app/job_daemon.lock</code>(内容为当前进程 PID,防止重复启动)</li><li>防重复:同一任务在同一分钟内只执行一次(<code>hasRunThisMinute</code> 查 JobLog)</li></ul><h3 id="运行方式" tabindex="-1">运行方式 <a class="header-anchor" href="#运行方式" aria-label="Permalink to "运行方式""></a></h3><p><strong>常用命令:</strong></p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">php</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> artisan</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> job:daemon</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 前台常驻(开发观察)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">php</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> artisan</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> job:daemon</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> --stop</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 停止</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">php</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> artisan</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> job:run</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 一次性执行(交给系统 cron 每分钟触发)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">nohup</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> php</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> artisan</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> job:daemon</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ></span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> storage/logs/job_daemon.log</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> 2>&1</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> &</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 后台</span></span></code></pre></div><h4 id="方式-A-前台运行-本地调试-" tabindex="-1">方式 A:前台运行(本地调试) <a class="header-anchor" href="#方式-A-前台运行-本地调试-" aria-label="Permalink to "方式 A:前台运行(本地调试)""></a></h4><div class="language-cmd vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">cmd</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">:: 项目根目录打开 CMD —— 启动</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">php artisan job:daemon</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">:: 停止(另开一个 CMD 窗口)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">php artisan job:</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">daemon</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> --</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">stop</span></span></code></pre></div><p><strong>启动成功输出:</strong></p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>[2026-10-07 22:10:06] Daemon 已启动 (PID: 32116)</span></span>
|
||
<span class="line"><span>[2026-10-07 22:10:06] 每分钟检查一次到期任务,按 Ctrl+C 优雅退出</span></span></code></pre></div><p><strong>运行日志:</strong></p><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>[2026-10-07 22:10:06] [执行] 定时任务演示 (cron: */5 * * * *)</span></span>
|
||
<span class="line"><span>[2026-10-07 22:10:06] [执行] 定时任务案例 (cron: */5 * * * *)</span></span>
|
||
<span class="line"><span>[2026-10-07 22:10:06] 本轮执行完成,共执行 2 个任务</span></span></code></pre></div><table tabindex="0"><thead><tr><th>标记</th><th>含义</th></tr></thead><tbody><tr><td><code>[执行]</code></td><td>任务已触发执行,括号内显示 cron 表达式</td></tr><tr><td><code>[跳过]</code></td><td>同一分钟内该任务已执行过,自动跳过(防重复)</td></tr><tr><td><code>[失败]</code></td><td>任务执行异常,后跟错误信息(单个任务失败不影响其他任务)</td></tr><tr><td><code>本轮执行完成</code></td><td>当前分钟扫描完毕,显示执行数量</td></tr></tbody></table><div class="tip custom-block"><p class="custom-block-title">TIP</p><p>没有到期任务时 Daemon 静默等待(不输出日志),属正常行为。</p></div><p><strong>前端联动:</strong> Daemon 启动后,「定时任务」模块顶部显示绿色「守护进程运行中 (PID: xxx)」按钮;未启动时显示灰色。</p><div class="tip custom-block"><p class="custom-block-title">状态检测原理</p><p>前端通过 <code>GET /api/job/daemonStatus</code> 轮询,后端读取 <code>storage/app/job_daemon.lock</code> 中的 PID 并检查进程是否存活。若进程非正常退出但锁文件残留,前端可能仍显示「运行中」——执行 <code>php artisan job:daemon --stop</code> 或删除锁文件清理。</p></div><h4 id="方式-B-Supervisor-管理-Linux-生产推荐-" tabindex="-1">方式 B:Supervisor 管理(Linux 生产推荐) <a class="header-anchor" href="#方式-B-Supervisor-管理-Linux-生产推荐-" aria-label="Permalink to "方式 B:Supervisor 管理(Linux 生产推荐)""></a></h4><div class="language-ini vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ini</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">; /etc/supervisor/conf.d/rxthinkcmf-job.conf</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">[</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#59873A;">program:rxthinkcmf-job</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">command</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">php /www/RXThinkCMF_Laravel13_EleVue/artisan job:daemon</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">directory</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">/www/RXThinkCMF_Laravel13_EleVue</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">autostart</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">true</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">autorestart</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">true</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">user</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">www-data</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">numprocs</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">1</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">redirect_stderr</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">true</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">stdout_logfile</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">/var/log/rxthinkcmf-job.log</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">stdout_logfile_maxbytes</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">10MB</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">stdout_logfile_backups</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">5</span></span></code></pre></div><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">sudo</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> supervisorctl</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> reread</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> &&</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> sudo</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> supervisorctl</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> update</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">sudo</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> supervisorctl</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> start</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> rxthinkcmf-job</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">sudo</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> supervisorctl</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> status</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> rxthinkcmf-job</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">tail</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> -f</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> /var/log/rxthinkcmf-job.log</span></span></code></pre></div><h4 id="方式-C-systemd-服务-Linux-生产推荐-" tabindex="-1">方式 C:systemd 服务(Linux 生产推荐) <a class="header-anchor" href="#方式-C-systemd-服务-Linux-生产推荐-" aria-label="Permalink to "方式 C:systemd 服务(Linux 生产推荐)""></a></h4><div class="language-ini vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ini</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">; /etc/systemd/system/rxthinkcmf-job.service</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">[</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#59873A;">Unit</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">Description</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">RXThinkCMF Job Daemon</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">After</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">network.target mysql.service</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">[</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#59873A;">Service</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">Type</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">simple</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">User</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">www-data</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">WorkingDirectory</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">/www/RXThinkCMF_Laravel13_EleVue</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">ExecStart</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">/usr/bin/php /www/RXThinkCMF_Laravel13_EleVue/artisan job:daemon</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">Restart</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">always</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">RestartSec</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">10</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">[</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#59873A;">Install</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">WantedBy</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">multi-user.target</span></span></code></pre></div><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">sudo</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> systemctl</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> enable</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> rxthinkcmf-job</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">sudo</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> systemctl</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> start</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> rxthinkcmf-job</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">sudo</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> systemctl</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> status</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> rxthinkcmf-job</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">sudo</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> journalctl</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> -u</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> rxthinkcmf-job</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> -f</span></span></code></pre></div><h4 id="方式-D-nohup-后台运行-简单场景-" tabindex="-1">方式 D:nohup 后台运行(简单场景) <a class="header-anchor" href="#方式-D-nohup-后台运行-简单场景-" aria-label="Permalink to "方式 D:nohup 后台运行(简单场景)""></a></h4><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">nohup</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> php</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> artisan</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> job:daemon</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ></span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> storage/logs/job_daemon.log</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> 2>&1</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> &</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">ps</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> aux</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> |</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> grep</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> job:daemon</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">kill</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $(</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">pgrep</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> -f</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> "</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">job:daemon</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span></span></code></pre></div><h4 id="Docker-环境" tabindex="-1">Docker 环境 <a class="header-anchor" href="#Docker-环境" aria-label="Permalink to "Docker 环境""></a></h4><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">docker</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> compose</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> exec</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> app</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> php</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> artisan</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> job:daemon</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 或以独立常驻容器运行 app 镜像的 artisan 命令</span></span></code></pre></div><h3 id="三种方式对比" tabindex="-1">三种方式对比 <a class="header-anchor" href="#三种方式对比" aria-label="Permalink to "三种方式对比""></a></h3><table tabindex="0"><thead><tr><th>特性</th><th>Crontab</th><th>Windows 计划任务</th><th>Daemon 守护进程</th></tr></thead><tbody><tr><td>适用系统</td><td>Linux / macOS</td><td>Windows</td><td>全平台</td></tr><tr><td>最小间隔</td><td>1 分钟</td><td>1 分钟</td><td>分钟级(每轮 sleep 60s)</td></tr><tr><td>资源占用</td><td>低(按需启动)</td><td>低(按需启动)</td><td>常驻内存</td></tr><tr><td>可靠性</td><td>高</td><td>高</td><td>高(配合 Supervisor/systemd)</td></tr><tr><td>日志追踪</td><td>需重定向</td><td>任务计划程序</td><td>自带输出</td></tr><tr><td>推荐场景</td><td>生产环境</td><td>Windows 生产</td><td>开发调试 / 不便配置 cron</td></tr></tbody></table><div class="tip custom-block"><p class="custom-block-title">推荐选择</p><ul><li><strong>Linux 生产环境</strong>:Crontab(简单可靠)</li><li><strong>Windows 生产环境</strong>:任务计划程序 或 Daemon + 计划任务守护</li><li><strong>Docker 环境</strong>:Daemon(容器内运行)</li><li><strong>本地开发调试</strong>:Daemon 前台运行(直接观察日志输出)</li></ul></div><h2 id="新建定时任务步骤" tabindex="-1">新建定时任务步骤 <a class="header-anchor" href="#新建定时任务步骤" aria-label="Permalink to "新建定时任务步骤""></a></h2><h3 id="_1-创建任务处理器" tabindex="-1">1. 创建任务处理器 <a class="header-anchor" href="#_1-创建任务处理器" aria-label="Permalink to "1. 创建任务处理器""></a></h3><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"><?</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;">php</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// app/Task/CleanLogTask.php(本步骤新建的处理器)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">namespace</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#2E8F82;--shiki-light-font-style:inherit;"> App</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;">\\</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#2E8F82;--shiki-light-font-style:inherit;">Task</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">/**</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> * 清理过期日志任务</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> *</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> * 数据库 url 字段:CleanLog</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> * 参数格式:{"days": 30}</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> */</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">class</span><span style="--shiki-dark:#97E1F1;--shiki-light:#2E8F82;"> CleanLogTask</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> extends</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#59873A;--shiki-light-font-style:inherit;"> BaseTask</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> /**</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> * 执行任务</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> *</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> * </span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">@param</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> array</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> $params 任务参数</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> * </span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">@return</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> string</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> 执行结果消息</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> * </span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">@throws</span><span style="--shiki-dark:#F286C4;--shiki-dark-font-style:italic;--shiki-light:#999999;--shiki-light-font-style:inherit;"> \\</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;">Exception</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> 执行失败时抛出</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> */</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> public</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> run</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">array</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">params</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> [])</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">:</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> string</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">days</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">params</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">[</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">days</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ??</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 30</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">cutoffDate</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> date</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">Y-m-d H:i:s</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> strtotime</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">-</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{$</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B56959;">days</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> days</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">));</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 清理登录日志</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">loginCount</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> LoginLog</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">where</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">create_time</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"><</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">cutoffDate</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-></span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">delete</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">();</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 清理操作日志</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">operCount</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> OperationLog</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">where</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">create_time</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"><</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">cutoffDate</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-></span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">delete</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">();</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 清理任务日志</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">jobCount</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> JobLog</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">where</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">start_time</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"><</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">cutoffDate</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-></span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">delete</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">();</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> "</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">已清理 </span><span style="--shiki-dark:#E7EE98;--shiki-light:#999999;">{</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">$</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B56959;">days</span><span style="--shiki-dark:#E7EE98;--shiki-light:#999999;">}</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> 天前的日志:登录日志 </span><span style="--shiki-dark:#E7EE98;--shiki-light:#999999;">{</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">$</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B56959;">loginCount</span><span style="--shiki-dark:#E7EE98;--shiki-light:#999999;">}</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> 条,操作日志 </span><span style="--shiki-dark:#E7EE98;--shiki-light:#999999;">{</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">$</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B56959;">operCount</span><span style="--shiki-dark:#E7EE98;--shiki-light:#999999;">}</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> 条,任务日志 </span><span style="--shiki-dark:#E7EE98;--shiki-light:#999999;">{</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">$</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B56959;">jobCount</span><span style="--shiki-dark:#E7EE98;--shiki-light:#999999;">}</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> 条</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">"</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><p>内置示例处理器:<code>app/Task/HelloWorldTask.php</code>(验证 daemon 调度)、<code>app/Task/SendSmsTask.php</code>(示例任务)。</p><h3 id="_2-在数据库-job-表中配置" tabindex="-1">2. 在数据库 job 表中配置 <a class="header-anchor" href="#_2-在数据库-job-表中配置" aria-label="Permalink to "2. 在数据库 job 表中配置""></a></h3><div class="language-sql vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">INSERT INTO</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;"> laravel_job (</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;"> job_name, job_alias, job_group, job_trigger,</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> url</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, params, cron_expression,</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;"> execute_policy, </span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">status</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, is_sync,</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;"> is_delete, create_user, create_time</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">) </span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">VALUES</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;"> (</span></span>
|
||
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">清理过期日志</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">CleanLog</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">系统维护</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">cron</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">,</span></span>
|
||
<span class="line"><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">CleanLog</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">{"days":30}</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">0 2 * * *</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">,</span></span>
|
||
<span class="line"><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 2</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;">1</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;">0</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">,</span></span>
|
||
<span class="line"><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 0</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">admin</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">, </span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">NOW</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">()</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">);</span></span></code></pre></div><p>(也可在「定时任务」管理界面新增。)</p><h3 id="_3-配置触发方式-三选一-" tabindex="-1">3. 配置触发方式(三选一) <a class="header-anchor" href="#_3-配置触发方式-三选一-" aria-label="Permalink to "3. 配置触发方式(三选一)""></a></h3><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 方式一:Linux Crontab</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">crontab</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> -e</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 添加:* * * * * cd /项目路径 && /usr/bin/php artisan job:run >> /dev/null 2>&1</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 方式二:Windows 计划任务(见上文 schtasks 示例)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 方式三:Daemon 守护进程</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">php</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> artisan</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> job:daemon</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 停止:php artisan job:daemon --stop</span></span></code></pre></div><h2 id="Service-配置-摘自-app-Services-JobService-php-实际代码-" tabindex="-1">Service 配置(摘自 <code>app/Services/JobService.php</code> 实际代码) <a class="header-anchor" href="#Service-配置-摘自-app-Services-JobService-php-实际代码-" aria-label="Permalink to "Service 配置(摘自 \`app/Services/JobService.php\` 实际代码)""></a></h2><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">class</span><span style="--shiki-dark:#97E1F1;--shiki-light:#2E8F82;"> JobService</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> extends</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#59873A;--shiki-light-font-style:inherit;"> BaseService</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> use</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> HasCrudOperations</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> HasQueryScopes</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> HasUniqueCheck</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> protected</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> string</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">modelClass</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> Job</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">class</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 任务名 / 任务别名模糊匹配</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> protected</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> array</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">pageLikeFields</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> [</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">job_name</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">job_alias</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">];</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 状态 / 任务分组精确匹配</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> protected</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> array</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">pageEqFields</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> [</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">status</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">job_group</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">];</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 任务别名全局唯一</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> protected</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> array</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">uniqueFields</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> [</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">job_alias</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">];</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><div class="info custom-block"><p class="custom-block-title">未配置字典翻译与文件字段</p><p>任务表的 <code>status</code>、<code>execute_policy</code> 等枚举直接以数值存储,前端按 <a href="/zh/modules/job.html">6.11 定时任务</a> 状态说明渲染,<code>JobService</code> 未声明 <code>serializeMaps</code> / <code>fileFields</code>。</p></div><h2 id="API-接口" tabindex="-1">API 接口 <a class="header-anchor" href="#API-接口" aria-label="Permalink to "API 接口""></a></h2><h3 id="任务管理" tabindex="-1">任务管理 <a class="header-anchor" href="#任务管理" aria-label="Permalink to "任务管理""></a></h3><table tabindex="0"><thead><tr><th>方法</th><th>路径</th><th>权限码</th><th>说明</th></tr></thead><tbody><tr><td>GET</td><td><code>/api/job/page</code></td><td>sys:job:page</td><td>分页列表</td></tr><tr><td>GET</td><td><code>/api/job/list</code></td><td>sys:job:list</td><td>全量列表</td></tr><tr><td>GET</td><td><code>/api/job/detail/{id}</code></td><td>sys:job:detail</td><td>详情</td></tr><tr><td>GET</td><td><code>/api/job/runOnce/{id}</code></td><td>sys:job:execute</td><td>手动执行一次</td></tr><tr><td>GET</td><td><code>/api/job/pause/{id}</code></td><td>sys:job:pause</td><td>暂停任务</td></tr><tr><td>GET</td><td><code>/api/job/resume/{id}</code></td><td>sys:job:resume</td><td>恢复任务</td></tr><tr><td>GET</td><td><code>/api/job/daemonStatus</code></td><td>—</td><td>守护进程状态</td></tr><tr><td>POST</td><td><code>/api/job/add</code></td><td>sys:job:add</td><td>新增任务</td></tr><tr><td>POST</td><td><code>/api/job/status</code></td><td>sys:job:update</td><td>设置状态</td></tr><tr><td>PUT</td><td><code>/api/job/update</code></td><td>sys:job:update</td><td>修改任务</td></tr><tr><td>DELETE</td><td><code>/api/job/delete/{id}</code></td><td>sys:job:delete</td><td>删除任务</td></tr><tr><td>DELETE</td><td><code>/api/job/batchDelete</code></td><td>sys:job:batchDelete</td><td>批量删除</td></tr></tbody></table><h3 id="任务日志" tabindex="-1">任务日志 <a class="header-anchor" href="#任务日志" aria-label="Permalink to "任务日志""></a></h3><table tabindex="0"><thead><tr><th>方法</th><th>路径</th><th>权限码</th><th>说明</th></tr></thead><tbody><tr><td>GET</td><td><code>/api/job/log/page</code></td><td>sys:job:page</td><td>日志分页</td></tr><tr><td>GET</td><td><code>/api/job/log/detail/{id}</code></td><td>sys:job:detail</td><td>日志详情</td></tr><tr><td>DELETE</td><td><code>/api/job/log/delete/{id}</code></td><td>sys:job:delete</td><td>删除日志</td></tr><tr><td>DELETE</td><td><code>/api/job/log/batchDelete</code></td><td>sys:job:batchDelete</td><td>批量删除</td></tr></tbody></table><h2 id="核心代码解析" tabindex="-1">核心代码解析 <a class="header-anchor" href="#核心代码解析" aria-label="Permalink to "核心代码解析""></a></h2><h3 id="Cron-表达式匹配-JobService-matchCronField-" tabindex="-1">Cron 表达式匹配(JobService::matchCronField) <a class="header-anchor" href="#Cron-表达式匹配-JobService-matchCronField-" aria-label="Permalink to "Cron 表达式匹配(JobService::matchCronField)""></a></h3><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">// app/Services/JobService.php(来自项目实际代码)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">/**</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> * 匹配 cron 字段</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> *</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> * 支持以下语法:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> * - *:匹配所有</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> * - */</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;">n:每隔</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> n</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> 个单位</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> *</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> -</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> n</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">-</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;">m:范围匹配</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> *</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> -</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> n</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;">m</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">...</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;">:逗号分隔的多值</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> *</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> -</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> n:单个值精确匹配</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> */</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">protected</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> matchCronField</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">string</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">cronField</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> int</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">current</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">:</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> bool</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> ($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">cronField</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ===</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">*</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#1E754F;"> true</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 处理 */n(每隔 n 分钟/小时等)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">preg_match</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#EE6666;--shiki-light:#B5695977;">'/</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">^</span><span style="--shiki-dark:#F286C4;--shiki-light:#BDA437;">\\*\\/</span><span style="--shiki-dark:#E7EE98;--shiki-light:#AB5E3F;">(</span><span style="--shiki-dark:#F286C4;--shiki-light:#BDA437;">\\d</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">+</span><span style="--shiki-dark:#E7EE98;--shiki-light:#AB5E3F;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">$</span><span style="--shiki-dark:#EE6666;--shiki-light:#B5695977;">/'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">cronField</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">m</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">))</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">current</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> %</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#AB5959;--shiki-light-font-style:inherit;">int</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">m</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">[</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;">1</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ===</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 0</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 处理 n-m(范围)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">preg_match</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#EE6666;--shiki-light:#B5695977;">'/</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">^</span><span style="--shiki-dark:#E7EE98;--shiki-light:#AB5E3F;">(</span><span style="--shiki-dark:#F286C4;--shiki-light:#BDA437;">\\d</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">+</span><span style="--shiki-dark:#E7EE98;--shiki-light:#AB5E3F;">)-(</span><span style="--shiki-dark:#F286C4;--shiki-light:#BDA437;">\\d</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">+</span><span style="--shiki-dark:#E7EE98;--shiki-light:#AB5E3F;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">$</span><span style="--shiki-dark:#EE6666;--shiki-light:#B5695977;">/'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">cronField</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">m</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">))</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">current</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> >=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#AB5959;--shiki-light-font-style:inherit;">int</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">m</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">[</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;">1</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> &&</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">current</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> <=</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#AB5959;--shiki-light-font-style:inherit;">int</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">m</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">[</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;">2</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">];</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 处理逗号分隔的多个值</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> if</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">strpos</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">cronField</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> !==</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#1E754F;"> false</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> {</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">values</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> array_map</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">intval</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> explode</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">cronField</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">));</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> in_array</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">($</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">current</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">values</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">);</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> }</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> // 单个值</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> (</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#AB5959;--shiki-light-font-style:inherit;">int</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">cronField</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ===</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">current</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><h3 id="防重复执行-JobService-hasRunThisMinute-" tabindex="-1">防重复执行(JobService::hasRunThisMinute) <a class="header-anchor" href="#防重复执行-JobService-hasRunThisMinute-" aria-label="Permalink to "防重复执行(JobService::hasRunThisMinute)""></a></h3><div class="language-php vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">php</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;">/**</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> * 检查任务在当前分钟是否已执行过</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> *</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> * Daemon 模式下,防止同一分钟内重复执行。</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> */</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">public</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> function</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;"> hasRunThisMinute</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;">int</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">jobId</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">:</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> bool</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">{</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">minuteStart</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> date</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">Y-m-d H:i</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> .</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">:00</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">minuteEnd</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> =</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> date</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">Y-m-d H:i</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> .</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">:59</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> return</span><span style="--shiki-dark:#97E1F1;--shiki-dark-font-style:italic;--shiki-light:#998418;--shiki-light-font-style:inherit;"> JobLog</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;">::</span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">where</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">job_id</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">jobId</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> -></span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">where</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">start_time</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">>=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">minuteStart</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> -></span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">where</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">(</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">start_time</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"><=</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> $</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">minuteEnd</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> -></span><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">count</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">()</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> ></span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 0</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">;</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">}</span></span></code></pre></div><h3 id="JobService-能力清单" tabindex="-1">JobService 能力清单 <a class="header-anchor" href="#JobService-能力清单" aria-label="Permalink to "JobService 能力清单""></a></h3><table tabindex="0"><thead><tr><th>方法</th><th>说明</th></tr></thead><tbody><tr><td><code>runPending()</code></td><td>扫描并执行全部到期任务,返回执行数</td></tr><tr><td><code>shouldRun($job)</code></td><td>解析 cron 判断任务是否到期</td></tr><tr><td><code>executeJob($job)</code></td><td>执行入口(策略检查 + 执行 + 记录 JobLog)</td></tr><tr><td><code>runOnce($id)</code></td><td>手动执行一次(忽略 cron)</td></tr><tr><td><code>setStatus($id, $status)</code> / <code>pause($id)</code> / <code>resume($id)</code></td><td>状态流转</td></tr><tr><td><code>executeHttp($url, $params)</code></td><td>HTTP 类任务执行</td></tr><tr><td><code>executeInternal($url, $params)</code></td><td>内部 Task 类执行(映射 <code>App\\Task\\{Name}Task</code>)</td></tr></tbody></table><h2 id="注意事项" tabindex="-1">注意事项 <a class="header-anchor" href="#注意事项" aria-label="Permalink to "注意事项""></a></h2><ol><li><strong>互斥运行</strong>:Cron 模式和 Daemon 模式不要同时使用,否则会导致任务重复执行</li><li><strong>防重复执行</strong>:Daemon 模式内置防重复机制,同一任务在同一分钟内不会重复执行</li><li><strong>错误隔离</strong>:单个任务执行失败不影响其他任务和主循环</li><li><strong>优雅退出</strong>:Daemon 支持 <code>SIGTERM</code>/<code>SIGINT</code> 信号,<code>Ctrl+C</code> 或 <code>kill</code> 均可优雅停止</li><li><strong>锁文件</strong>:Daemon 的锁文件位于 <code>storage/app/job_daemon.lock</code>,异常退出后残留锁会自动检测并清理</li><li><strong>Windows 兼容</strong>:Daemon 在 Windows 下可正常运行,但信号处理(pcntl)不可用,需通过 <code>--stop</code> 参数或 <code>taskkill</code> 停止</li><li><strong>日志截断</strong>:执行结果消息截取前 500 字符,异常信息截取前 2000 字符写入 job_log</li><li><strong>create_user</strong>:命令行执行的任务日志中 <code>create_user</code> 由 HasAuditColumns trait 自动处理(无登录用户时为空)</li></ol><h2 id="常见问题" tabindex="-1">常见问题 <a class="header-anchor" href="#常见问题" aria-label="Permalink to "常见问题""></a></h2><h3 id="Q-任务不执行-" tabindex="-1">Q: 任务不执行? <a class="header-anchor" href="#Q-任务不执行-" aria-label="Permalink to "Q: 任务不执行?""></a></h3><p>A: 检查以下几点:</p><ol><li>任务状态是否为 <code>1</code>(运行中)</li><li>Cron 表达式格式是否正确(5 段)</li><li>Crontab 是否已配置且 cron 服务已启动</li><li>PHP 路径是否正确(建议使用绝对路径)</li><li>手动执行 <code>php artisan job:run</code> 是否正常</li></ol><h3 id="Q-任务重复执行-" tabindex="-1">Q: 任务重复执行? <a class="header-anchor" href="#Q-任务重复执行-" aria-label="Permalink to "Q: 任务重复执行?""></a></h3><p>A: Daemon 模式下检查 <code>hasRunThisMinute</code> 是否生效;Crontab 模式下确保只有一个 cron 在触发(<code>crontab -l</code> 检查重复项)。</p><h3 id="Q-任务执行超时-" tabindex="-1">Q: 任务执行超时? <a class="header-anchor" href="#Q-任务执行超时-" aria-label="Permalink to "Q: 任务执行超时?""></a></h3><p>A: 检查 PHP 的 <code>max_execution_time</code> 配置,长时间任务建议拆分或在处理器内调大 <code>set_time_limit(0)</code>。</p><h3 id="Q-如何查看任务执行日志-" tabindex="-1">Q: 如何查看任务执行日志? <a class="header-anchor" href="#Q-如何查看任务执行日志-" aria-label="Permalink to "Q: 如何查看任务执行日志?""></a></h3><p>A: 两种方式:</p><ol><li><strong>控制台实时日志</strong>:Daemon 前台运行时,<code>[执行]</code>、<code>[跳过]</code>、<code>[失败]</code> 直接输出到终端</li><li><strong>数据库持久化日志</strong>:通过 <code>GET /api/job/log/page</code> 查询,或直接查 <code>laravel_job_log</code> 表</li></ol><h3 id="Q-Daemon-控制台没有新日志输出-是卡住了吗-" tabindex="-1">Q: Daemon 控制台没有新日志输出,是卡住了吗? <a class="header-anchor" href="#Q-Daemon-控制台没有新日志输出-是卡住了吗-" aria-label="Permalink to "Q: Daemon 控制台没有新日志输出,是卡住了吗?""></a></h3><p>A: 不是。Daemon 每分钟检查一次,没有到期任务时静默等待,不输出任何日志。</p><h3 id="Q-Windows-下-Daemon-如何启动和停止-" tabindex="-1">Q: Windows 下 Daemon 如何启动和停止? <a class="header-anchor" href="#Q-Windows-下-Daemon-如何启动和停止-" aria-label="Permalink to "Q: Windows 下 Daemon 如何启动和停止?""></a></h3><p>A: 项目根目录打开 CMD:</p><div class="language-cmd vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">cmd</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">:: 启动</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">php artisan job:daemon</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">:: 停止(另开一个 CMD 窗口)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F6F6F4;--shiki-light:#393A34;">php artisan job:</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">daemon</span><span style="--shiki-dark:#F286C4;--shiki-light:#AB5959;"> --</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#B07D48;">stop</span></span></code></pre></div><p>如提示 <code>Daemon 已在运行中 (PID: xxx)</code>,先执行 <code>php artisan job:daemon --stop</code> 停止旧进程,或手动删除 <code>storage/app/job_daemon.lock</code>。</p><h3 id="Q-提示找不到-Task-类-" tabindex="-1">Q: 提示找不到 Task 类? <a class="header-anchor" href="#Q-提示找不到-Task-类-" aria-label="Permalink to "Q: 提示找不到 Task 类?""></a></h3><p>A: 确认 <code>url</code> 字段的类名与 <code>app/Task/</code> 下的类文件一致(命名空间 <code>App\\Task</code>),且类名采用大驼峰(<code>SendSms</code> → <code>SendSmsTask</code>)。</p>`,107)])])}const g=i(h,[["render",l]]);export{o as __pageData,g as default};
|