本文目录导读:

- ThinkPHP自带的多应用/命令行模式(推荐)
- 使用Cron直接调用
- 使用Laravel式调度器(ThinkPHP扩展)
- 使用系统调度服务(Linux systemd)
- 在Windows环境下使用任务计划程序
- 高级:数据库驱动调度
- 注意事项与最佳实践
- 总结与选型建议
在ThinkPHP项目中实现任务调度(Task Scheduling)与Cron,有多种方案可以选择,具体取决于你的项目需求和运行环境。
以下是几种主流且实用的实现方式:
ThinkPHP自带的多应用/命令行模式(推荐)
这是最规范的实现方式,适合复杂业务逻辑。
1 创建自定义命令
在 app/command/ 目录下创建命令类(如果目录不存在则创建):
<?php
// app/command/TestTask.php
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\facade\Db;
class TestTask extends Command
{
protected function configure()
{
$this->setName('task:test')
->setDescription('测试定时任务');
}
protected function execute(Input $input, Output $output)
{
// 你的业务逻辑代码
$output->writeln('任务开始执行: ' . date('Y-m-d H:i:s'));
// 示例:清理过期日志
Db::name('logs')->where('create_time', '<', time() - 86400*7)->delete();
$output->writeln('任务执行完成');
}
}
2 注册命令
在 config/console.php 中注册你的命令:
// config/console.php
return [
'commands' => [
\app\command\TestTask::class,
],
];
3 测试运行
# 在项目根目录执行 php think task:test
使用Cron直接调用
如果你的服务器环境是Linux/macOS,这是最简单直接的方式。
1 编辑Cron配置
crontab -e
2 添加Cron规则
# 每天凌晨2点执行 0 2 * * * cd /path/to/your/project && php think task:test >> storage/logs/cron.log 2>&1 # 每5分钟执行一次 */5 * * * * cd /path/to/your/project && php think task:test # 每小时的第一分钟执行 1 * * * * cd /path/to/your/project && php think task:test # 每天上午9点30分执行 30 9 * * * cd /path/to/your/project && php think task:test
使用Laravel式调度器(ThinkPHP扩展)
如果你喜欢Laravel的Scheduler方式,可以安装第三方扩展。
1 安装topthink/think-scheduler
composer require topthink/think-scheduler
2 配置调度器
在 config/scheduler.php 配置你的任务:
<?php
// config/scheduler.php
return [
// 调度任务定义
'tasks' => [
[
'schedule' => '0 2 * * *', // cron表达式
'task' => \app\command\TestTask::class,
],
[
'schedule' => '*/5 * * * *',
'command' => 'git pull', // 也可以执行系统命令
],
],
];
3 然后在Cron中添加一行:
* * * * * cd /path/to/project && php think schedule:run >> storage/logs/schedule.log 2>&1
使用系统调度服务(Linux systemd)
对于运行在稳定服务器上的应用,可以使用systemd进行管理。
1 创建systemd service
# /etc/systemd/system/think-task.service [Unit] Description=ThinkPHP Task Runner After=network.target [Service] Type=oneshot User=www-data WorkingDirectory=/var/www/your-project ExecStart=/usr/bin/php think task:test
2 创建timer
# /etc/systemd/system/think-task.timer [Unit] Description=Run ThinkPHP task every minute [Timer] OnCalendar=*-*-* * *:00:00 Persistent=true [Install] WantedBy=timers.target
3 启用定时器
systemctl daemon-reload systemctl enable think-task.timer systemctl start think-task.timer
在Windows环境下使用任务计划程序
如果这是Windows环境:
1 创建批处理文件
@echo off cd /d C:\path\to\your\project php think task:test
2 添加任务计划
- 打开“任务计划程序”
- 创建基本任务
- 设置触发器(每天/每周等)
- 设置操作为“启动程序”
- 选择刚创建的
.bat文件
高级:数据库驱动调度
对于多台服务器或需要动态调度的场景,可以使用数据库驱动的方式:
1 创建任务表
CREATE TABLE `task_schedules` ( `id` int(11) NOT NULL AUTO_INCREMENT, `task_name` varchar(100) NOT NULL, `cron_expression` varchar(100) NOT NULL, `last_run` datetime DEFAULT NULL, `status` tinyint(1) DEFAULT '1', PRIMARY KEY (`id`) ) ENGINE=InnoDB;
2 统一调度入口
<?php
// app/command/Scheduler.php
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\facade\Db;
class Scheduler extends Command
{
protected function configure()
{
$this->setName('schedule:run')
->setDescription('运行所有的定时任务');
}
protected function execute(Input $input, Output $output)
{
$tasks = Db::name('task_schedules')
->where('status', 1)
->select();
foreach ($tasks as $task) {
if ($this->shouldRun($task)) {
// 执行任务
$this->runTask($task);
// 更新最后运行时间
Db::name('task_schedules')
->where('id', $task['id'])
->update(['last_run' => date('Y-m-d H:i:s')]);
$output->writeln("执行任务: " . $task['task_name']);
}
}
}
private function shouldRun($task)
{
// 解析cron表达式并判断是否应该执行
// ... 这里需要实现cron表达式的解析逻辑
$lastRun = strtotime($task['last_run']);
$now = time();
// 简单示例:每分钟执行一次
return ($now - $lastRun) >= 60;
}
private function runTask($task)
{
// 根据task_name分派到具体的执行逻辑
switch ($task['task_name']) {
case 'send_email':
// 发送邮件逻辑
break;
// ... 其他任务
}
}
}
注意事项与最佳实践
1 日志记录
protected function execute(Input $input, Output $output)
{
try {
// 业务逻辑
Log::info('任务执行成功: ' . date('Y-m-d H:i:s'));
} catch (\Exception $e) {
Log::error('任务执行失败: ' . $e->getMessage());
}
// 或通过输出重定向到日志文件
$output->writeln('Task completed at: ' . date('Y-m-d H:i:s'));
}
2 避免任务重叠
// 使用文件锁防止任务重复执行
if (!file_exists('/tmp/task.lock')) {
file_put_contents('/tmp/task.lock', time());
try {
// 业务逻辑
} finally {
unlink('/tmp/task.lock');
}
}
3 环境变量区分
// 在任务中判断环境
if (app()->isDebug()) {
// 开发环境
} else {
// 生产环境
}
总结与选型建议
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| ThinkPHP命令 + Cron | 大多数项目 | 简单、灵活 | 需要手动维护Cron |
| ThinkPHP Scheduler扩展 | Laravel迁移项目 | 语法熟悉 | 依赖第三方库 |
| systemd定时器 | Linux服务器 | 稳定、可监控 | 学习成本稍高 |
| 数据库驱动调度 | 多服务器/动态调度 | 可动态管理 | 实现复杂 |
推荐组合:
- 使用 ThinkPHP命令 + Linux Cron 作为基础方案
- 配合 日志系统 + 监控报警 保证任务可靠性
- 使用 队列(如
think-queue)处理耗时任务
这样既能保持代码的清晰和可维护性,又能充分利用操作系统的稳定性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播