[原創]php任務調度器 hellogerard/jobby

簡介

一個強大的php層面上的定時任務調度器, 無需修改系統層面的crontabgit

實際中, php 結合 crontab 來實現定時任務是一種經得住考驗的實踐, 但每次新增/修改定時任務項時都須要去修改系統的crontab, 這會帶來兩個麻煩: 一個是繁瑣, 一個是難以版本控制.github

特色:shell

  • 只需維護一個crontab主做業
  • 子做業徹底由PHP編寫
  • 支持標準crontab的調度時間格式
  • 做業執行超時時可防止運行多個做業副本
  • 做業執行出錯退出時發送郵件通知
  • 能夠其餘用戶身份執行(若主crontab執行用戶具備sudo權限)
  • 支持僅在某個主機名上運行
  • 理論上的Windows支持(包做者未測試過)

相關連接:服務器

  • https://packagist.org/packages/hellogerard/jobby
  • https://github.com/jobbyphp/jobby

安裝

php 5.4閉包

composer require "hellogerard/jobby:3.4.1"

注意版本不要用3.4.1以上的, 會出問題(儘管packagist裏3.4.2和3.4.3寫着php>=5.4, 但實際會出問題)composer

php 更高版本測試

composer require hellogerard/jobby

配置crontab主做業ui

* * * * * cd /path/to/project && php jobby.php &>/dev/null

使用示例文件this

cp vendor/hellogerard/jobby/resources/jobby.php .

標準使用

// 加載composer autoload
require_once __DIR__ . '/vendor/autoload.php';

// 建立Jobby實例
$jobby = new Jobby\Jobby();

// 每一個job都有一個惟一名稱
$jobby->add('CommandExample', [

    // 運行一個shell命令
    'command'  => 'ls',
    
    // 運行一個閉包(與 'command' 互斥)
    //'closure'  => function() {
    //    echo "I'm a function!\n";
    //    return true;
    //},

    // 支持通用調度配置
    'schedule' => '0 * * * *',
    
    // 可以使用日期時間字符串
    //'schedule' => '2017-05-03 17:15:00',
    
    // 使用閉包返回boolean來肯定是否執行
    //'schedule' => function(DateTimeImmutable $now) {
    //    // Run on even minutes
    //    return $now->format('i') % 2 === 0;
    //},

    
    // 標準輸出/標準錯誤會寫入到指定日誌文件
    'output'   => 'logs/command.log',
    
    // 臨時關閉某個任務
    'enabled'  => false,
]);

$jobby->run();

選項

每一個任務的必須選項

Key Type Description
schedule string Crontab schedule format (man -s 5 crontab) or DateTime format (Y-m-d H:i:s) or callable (function(): Bool { /* ... */ })
command string The shell command to run (exclusive-or with closure)
closure Closure The anonymous PHP function to run (exclusive-or with command)

如下的選項列表可應用於單個任務或全局任務(經過傳入 Jobby構造器).

全局選項將會做爲每一個任務的默認配置, 單個任務可覆蓋全局選項.

Option Type Default Description
runAs string null Run as this user, if crontab user has sudo privileges
debug boolean false Send jobby internal messages to 'debug.log'
Filtering 過濾 Options to determine whether the job should run or not
environment string null or getenv('APPLICATION_ENV') Development environment for this job
runOnHost string gethostname() Run jobs only on this hostname
maxRuntime integer null Maximum execution time for this job (in seconds)
enabled boolean true Run this job at scheduled times
haltDir string null A job will not run if this directory contains a file bearing the job's name
Logging 日誌 Options for logging
output string /dev/null Redirect stdout and stderr to this file
output_stdout string value from output option Redirect stdout to this file
output_stderr string value from output option Redirect stderr to this file
dateFormat string Y-m-d H:i:s Format for dates on jobby log messages
Mailing 郵件 Options for emailing errors
recipients string null Comma-separated string of email addresses
mailer string sendmail Email method: sendmail or smtp or mail
smtpHost string null SMTP host, if mailer is smtp
smtpPort integer 25 SMTP port, if mailer is smtp
smtpUsername string null SMTP user, if mailer is smtp
smtpPassword string null SMTP password, if mailer is smtp
smtpSecurity string null SMTP security option: ssl or tls, if mailer is smtp
smtpSender string jobby@ The sender and from addresses used in SMTP notices
smtpSenderName string Jobby The name used in the from field for SMTP messages

項目實踐

項目存在多個不一樣遊戲服, 且每一個服使用的配置文件不同, 所以執行定時任務時需對每一個服單獨執行, 特建立crontab.php 文件用於針對不一樣服分別調用 jobby.php

crontab配置

* * * * * cd /path/to/project && php crontab.php &>/dev/null

crontab.php

<?php
// 服務器列表, 實際是從其餘地方讀取的
$servers = ["s1", "s2", "s3", "s4"];
foreach ($servers as $server) {
    $cmd = sprintf("php jobby.php %s &>/dev/null &", $server);
    exec($cmd);
    var_dump(compact('cmd'));
}

jobby.php

<?php
// 環境配置
// ...

$server = $argv[1];    
 
$cmdPrefix = "php dispatcher.php $server ";

$jobby = new \Jobby\Jobby([
    'output' => "具體的日誌輸出文件路徑",
]);
$jobs = require("jobby_config.php");
foreach ($jobs as $name => $job) {
    if (isset($config['command'])) {
        $config['command'] = $cmdPrefix.$config['command'];
    }
    $jobby->add($name, $job);
}
$jobby->run();

jobby_config.php

<?php
return [
    "check_index" => [
        'command' => "month_check_index",
        'schedule' => '30 5 1 * *',
        'maxRuntime' => 600,
    ],
    
    'minute_stats' => [
        'command' => "minute_stats",
        'schedule' => '* * * * *',
        'maxRuntime' => 300,
        'enabled' => true,
    ],
];

dispatcher.php 加載具體服的具體環境, 並調用實際要運行的php定時任務代碼

$server = $argv[1];
$command = $argv[2];

// 加載具體服的環境配置
// ...

// 執行具體定時任務代碼(此處忽略異常處理)
require __DIR__ . DIRECTORY_SEPARATOR . "jobs" . DIRECTORY_SEPARATOR . $command . ".php";

jobs/month_check_index.php

<?php
// 具體任務

jobs/minute_stats.php

<?php
// 具體任務
相關文章
相關標籤/搜索