PHP项目怎么实现定时任务?

wen PHP项目 8

本文目录导读:

PHP项目怎么实现定时任务?

  1. ✅ 推荐:系统Cron Job(Linux/Mac)
  2. 🏢 企业级方案:任务调度器
  3. 🔄 纯PHP实现:死循环检查
  4. 🌐 云服务方案
  5. 🔍 Windows环境方案
  6. ⚡ 高性能方案:Worker模式
  7. 最佳实践建议
  8. 选择建议

在PHP项目中实现定时任务,主要有以下几种常见方式,我按照推荐程度和适用场景为你介绍:

✅ 推荐:系统Cron Job(Linux/Mac)

这是最可靠、最常用的方法,适用于生产环境。

基本用法

# 编辑crontab
crontab -e
# 每分钟执行一次PHP脚本
* * * * * /usr/bin/php /path/to/your/script.php
# 每天凌晨2点执行
0 2 * * * /usr/bin/php /path/to/your/script.php
# 每周一上午9点
0 9 * * 1 /usr/bin/php /path/to/your/script.php

PHP脚本示例

<?php
// /path/to/your/script.php
// 避免超时
set_time_limit(0);
// 执行任务
try {
    // 你的业务逻辑
    echo "任务开始执行: " . date('Y-m-d H:i:s') . "\n";
    // 示例:清理过期数据
    $db = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
    $db->exec("DELETE FROM temp_data WHERE expire_time < NOW()");
    echo "任务执行完成\n";
} catch (Exception $e) {
    // 记录错误日志
    file_put_contents('/var/log/cron-error.log', 
        date('Y-m-d H:i:s') . ' - ' . $e->getMessage() . "\n", 
        FILE_APPEND
    );
}

🏢 企业级方案:任务调度器

适合复杂的定时任务管理。

Laravel任务调度(推荐)

Laravel提供了优雅的调度语法:

// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
    // 基本调度
    $schedule->command('emails:send')
             ->daily()
             ->at('13:00');
    // 复杂调度
    $schedule->call(function () {
        // 清理逻辑
    })->everyFiveMinutes()
      ->withoutOverlapping();
    // 每分钟执行
    $schedule->command('sync:data')
             ->everyMinute()
             ->runInBackground();
}
// 然后在服务器上添加一条cron
// * * * * * cd /path-to-project && php artisan schedule:run >> /dev/null 2>&1

轻量级调度库

如果不使用框架,可以用 cron-expression 库:

// composer require mtdowling/cron-expression
use Cron\CronExpression;
$cron = CronExpression::factory('*/5 * * * *');
if ($cron->isDue()) {
    // 执行任务
}

🔄 纯PHP实现:死循环检查

适合本地开发或简单场景:

<?php
// cron_runner.php
set_time_limit(0);
ignore_user_abort(true);
while (true) {
    $now = time();
    $lastRun = file_get_contents('/tmp/last_run.txt') ?: 0;
    // 检查是否超过5分钟
    if (($now - $lastRun) >= 300) {
        try {
            // 执行任务
            echo date('Y-m-d H:i:s') . " - 执行定时任务\n";
            // 记录执行时间
            file_put_contents('/tmp/last_run.txt', $now);
        } catch (Exception $e) {
            error_log($e->getMessage());
        }
    }
    // 每10秒检查一次
    sleep(10);
}

🌐 云服务方案

使用外部服务

  • EasyCron - 提供Web界面管理cron任务
  • Cron-Job.org - 免费在线cron服务
  • Google Cloud Scheduler - 企业级定时服务
  • AWS CloudWatch Events - AWS生态集成

示例:使用Webhooks

// 创建API端点
Route::post('/webhook/cleanup', function () {
    // 验证密钥
    if (request('secret') !== env('CRON_SECRET')) {
        abort(401);
    }
    // 执行清理
    CleanupService::run();
    return response()->json(['status' => 'success']);
});

🔍 Windows环境方案

Windows任务计划程序

# 创建计划任务
SchTasks /Create /SC MINUTE /MO 5 /TN "PHP Task" /TR "php.exe C:\path\to\script.php"

PHP服务方式

// 使用WScript运行
$WshShell = new COM("WScript.Shell");
$WshShell->Run("php schedule.php", 0, false);

⚡ 高性能方案:Worker模式

适合需要频繁执行的秒级任务:

<?php
// worker.php
// 使用pcntl扩展(仅支持Linux)
declare(ticks = 1);
// 信号处理
pcntl_signal(SIGTERM, function () {
    exit(0);
});
// 进程池
$maxProcesses = 5;
$processes = [];
while (true) {
    // 检查子进程数量
    while (count($processes) >= $maxProcesses) {
        foreach ($processes as $pid => $task) {
            $result = pcntl_waitpid($pid, $status, WNOHANG);
            if ($result > 0) {
                unset($processes[$pid]);
            }
        }
        usleep(100000); // 100ms
    }
    // 派生子进程执行任务
    $pid = pcntl_fork();
    if ($pid == -1) {
        // fork失败
        continue;
    } elseif ($pid == 0) {
        // 子进程执行任务
        executeTask();
        exit(0);
    } else {
        // 父进程记录子进程
        $processes[$pid] = time();
    }
    sleep(1); // 每秒检查是否需要创建新进程
}

最佳实践建议

记录日志

function logCron($message, $level = 'info') {
    $log = sprintf(
        "[%s] [%s] %s\n",
        date('Y-m-d H:i:s'),
        strtoupper($level),
        $message
    );
    file_put_contents('/var/log/php-cron.log', $log, FILE_APPEND);
}

防止重复执行

function acquireLock($taskName) {
    $lockFile = "/tmp/{$taskName}.lock";
    if (file_exists($lockFile)) {
        $pid = file_get_contents($lockFile);
        if (posix_kill($pid, 0)) {
            return false; // 任务正在运行
        }
    }
    file_put_contents($lockFile, getmypid());
    return true;
}
function releaseLock($taskName) {
    unlink("/tmp/{$taskName}.lock");
}

监控告警

// 在关键任务中添加
function notifyFailure($taskName, $error) {
    // 发送邮件
    mail('admin@example.com', "Cron Failed: $taskName", $error);
    // 或者使用Slack Webhook
    $data = json_encode(['text' => "❌ Cron任务 $taskName 失败: $error"]);
    file_get_contents('https://hooks.slack.com/services/YOUR/WEBHOOK/URL', 
        false, stream_context_create(['http' => [
            'method' => 'POST',
            'header' => 'Content-Type: application/json',
            'content' => $data
        ]])
    );
}

选择建议

场景 推荐方案
个人项目/小站点 系统Cron + PHP脚本
企业级应用 Laravel调度 + 系统Cron
微服务架构 云服务调度器
需要秒级精度 Worker模式
团队协作项目 框架内置调度
跨平台需求 第三方服务

核心建议:除非有特殊需求,否则使用系统cron + PHP框架的调度功能是最稳定、最容易维护的方案。

抱歉,评论功能暂时关闭!