deploy-dog/slavedriver

基于PHP的cron作业执行器。管理、监控、记录和响应预定任务中的问题。

v1.1.0 2021-04-26 14:21 UTC

This package is auto-updated.

Last update: 2024-08-26 21:12:19 UTC


README

基于PHP的cron作业执行器。管理、监控、记录和响应预定任务中的问题。由deploy.dog团队创建,最初用于内部使用,但经过修改和发布,供其他人享受。由deploy.dog创建,最初用于内部使用,但发布供其他人享受。

Travis CI Packagist Packagist Packagist Packagist PHP 7 ready

deploy.dog - Finally, website deployments done right!

要求

  • PHP 5.6, 7.0, 7.1或HHVM
  • 基于Unix的操作系统,如Linux、FreeBSD或MacOS (目前不支持Windows)

安装(通过Composer显然)

composer require deploy-dog/slavedriver

使用

创建描述您的作业的文件。

我们建议在项目根目录中创建一个名为slavedriver.php的文件,以下示例中将使用此文件。

此文件的更详细示例可在此处查看这里,但基本如下

// You'll need autoloading
require_once __DIR__ . '/vendor/autoload.php';

// We recommend scrapbook for your PSR-16 compatible cache, but use whatever you like!
// This example is using Scrapbook and Flysystem to write a cache file to the disk, but you'll
// probably want to use Redis or something better like that
$adapter = new \League\Flysystem\Adapter\Local('/tmp/dd.slavedriver.cache', LOCK_EX);
$filesystem = new \League\Flysystem\Filesystem($adapter);
$cache = new \MatthiasMullie\Scrapbook\Adapters\Flysystem($filesystem);
$simpleCache = new \MatthiasMullie\Scrapbook\Psr16\SimpleCache($cache);

// In this example, we use phossa2/event which is a PSR-14 event manager.
// PSR-14 is only "proposed" at this stage. Once PSR-14 is "accepted" we'll update the required interface.
// You can use anything that implments \Phossa2\Event\Interfaces\EventManagerInterface (which is a copy of PSR-14),
// it doesn't actually have to be phossa2/event
$eventsDispatcher = new \Phossa2\Event\EventDispatcher();
$eventsDispatcher->attach(\deploydog\Slavedriver\Slavedriver::EVENT_SLAVEDRIVER_ALL, function(\Phossa2\Event\Event $event) {
    $job = $event->getTarget();
    // See Events in the readme below for details on events
});

// Instantiate Slavedriver
$slavedriver = new \deploydog\Slavedriver\Slavedriver($simpleCache, $eventsDispatcher);

// Want logging (in addition to events)? See the Logging section of the readme below

// You can set the Slave Name that the machine running this job has (so it know which jobs to do).
// We'll look at the following (in this order)
// Manually set using $slavedriver->setSlaveName()
// Environment var "SLAVEDRIVER_SLAVE_NAME"
// Node hostname (from php's gethostname() function)
$slavedriver->setSlaveName('test1');

// Create a job
$job = new \deploydog\Slavedriver\Job('Sleep for a bit');
$job->setCommand('sleep 10');
$job->setTimeout(14);
$job->setWarnIfNotFinishedAfterSeconds(11);
$job->setSchedule('* * * * *');
$job->setSlaves(['test1']); // Optional, default to all slaves

// Add the job to Slavedriver
$slavedriver->addJob($job);

// Add more jobs like with the example above..

// Alternatively (or in addition) if you have lots of jobs you might want to include one per file
// and get Slavedriver to recursively look in directory for jobs
// Your included files should return an instance of the Job object.
$slavedriver->addAllJobsInDirectory(__DIR__.'/DirWithJobs');

// Run the required jobs
$slavedriver->run();

运行Slavedriver

您需要获取某些内容(例如实际的系统crontab)来每1分钟运行您的Slavedriver文件(这个时间间隔很重要,不要更改它)。

* * * * * cd /path/to/project && php slavedriver.php 1>> /dev/null 2>&1

事件

在整个过程中分发事件,您可以监听这些事件。您可以使用任何PSR-14(事件管理器)兼容的事件管理器。PSR-14目前处于“提议”阶段,因此我们应该预计它会发生变化。如果您目前没有且不想自己实现,我们建议使用phossa2/event作为您的PSR-14事件管理器。由于PSR-14尚未推出,我们需要一个实现Phossa2\Event\Interfaces\EventManagerInterface的类,如果您不想使用phossa2/event,您可以编写其他实现该相同类的代码。我知道这并不理想,我们预计在v2版本中(当PSR-14获得批准时)将进行更改。

您可以监听以下事件以监控您的Slavedriver作业并相应地采取行动。

提示:如果您想传递额外的数据,例如是否在作业失败时唤醒人们,请使用作业的CustomData

捕获事件

处理特定事件

$eventsDispatcher = new \Phossa2\Event\EventDispatcher(); // This is the same one you passed into Slavedriver on construct
$eventsDispatcher->attach(\deploydog\Slavedriver\Slavedriver::EVENT_JOB_OUTPUT_STDOUT, function(\Phossa2\Event\Event $event) {
     $job = $event->getTarget();
     $stdOut = $event->getParam('stdOut');
    
     // Log $stdOut somewhere, this can be called multiple times for each job and will be given any
     // new stdOut since the last call. You can then append this to the previous stdOut of the job
     // Likewise the event "slavedriver.job.output.stderr" will give you the stdErr in $event->getParam('stdErr')
});

处理所有Slavedriver事件

$eventsDispatcher = new \Phossa2\Event\EventDispatcher(); // This is the same one you passed into Slavedriver on construct
$eventsDispatcher->attach(\deploydog\Slavedriver\Slavedriver::EVENT_SLAVEDRIVER_ALL, function(\Phossa2\Event\Event $event) {
    $job = $event->getTarget();

    if ($job instanceof \deploydog\Slavedriver\Job) {
        echo 'Got event "'.$event->getName().'" on job "'.$job->getName().'"'."\n";
    } else {
        echo 'Got event "'.$event->getName().'"'."\n";
    }

    if ($event->getName() == \deploydog\Slavedriver\Slavedriver::EVENT_JOB_OUTPUT_STDOUT){
        echo 'stdOut > ' . $event->getParam('stdOut')."\n";
    } else if ($event->getName() == \deploydog\Slavedriver\Slavedriver::EVENT_JOB_OUTPUT_STDERR){
        echo 'stdErr > ' . $event->getParam('stdErr')."\n";
    }
});

Slavedriver本身启动(应该大约每1分钟启动一次)

  • 事件:slavedriver.started
  • 事件常量:Slavedriver::EVENT_SLAVEDRIVER_STARTED
  • 事件目标:
  • 事件参数:

作业开始

  • 事件:slavedriver.job.started
  • 事件常量:Slavedriver::EVENT_JOB_STARTED
  • 事件目标:Job对象
  • 事件参数:

作业成功完成

  • 事件:slavedriver.job.finished.success
  • 事件常量:Slavedriver::EVENT_JOB_FINISHED_SUCCESS
  • 事件目标:Job对象
  • 事件参数:

作业以错误结束(基于退出代码)

  • 事件:slavedriver.job.finished.error
  • 事件常量:Slavedriver::EVENT_JOB_FINISHED_ERROR
  • 事件目标:Job对象
  • 事件参数
    • exitCode = 命令的退出代码

作业标准输出数据(这每隔几秒会调用一次,并附加额外的数据)

  • 事件:slavedriver.job.output.stdout
  • 事件常量:Slavedriver::EVENT_JOB_OUTPUT_STDOUT
  • 事件目标:Job对象
  • 事件参数
    • stdOut = 自上次触发此事件以来的标准输出数据

作业标准错误数据(每几秒钟调用一次,并添加额外的数据)

  • 事件:slavedriver.job.output.stderr
  • 事件常量:Slavedriver::EVENT_JOB_OUTPUT_STDERR
  • 事件目标:Job对象
  • 事件参数
    • stdErr = 自上次触发此事件以来的标准错误数据

当达到超时值时,作业仍在运行(并且它已经被杀死)

  • 事件:slavedriver.job.timeout
  • 事件常量:Slavedriver::EVENT_JOB_TIMEOUT
  • 事件目标:Job对象
  • 事件参数:

作业应该已经启动,但最后一个实例仍在运行,它们不能重叠

  • 事件:slavedriver.job.last_instance_still_running
  • 事件常量:Slavedriver::EVENT_JOB_LAST_INSTANCE_STILL_RUNNING
  • 事件目标:Job对象
  • 事件参数:

作业仍在运行,但预期的运行时间已过(作业没有被杀死)

  • 事件:slavedriver.job.expected_runtime_elapsed
  • 事件常量:Slavedriver::EVENT_JOB_EXPECTED_RUNTIME_ELAPSED
  • 事件目标:Job对象
  • 事件参数:

日志记录

日志记录由任何兼容PSR-3的记录器提供。如果您愿意,可以为不同的消息提供自定义日志级别,或者保留默认的日志级别,这些默认级别是合理的。要设置日志记录,请在Slavedriver对象上调用setLogger()方法,传递PSR-3记录器和可选的日志级别。

$logger = new \Monolog\Logger('Slavedriver');
$logger->pushHandler(new \Monolog\Handler\StreamHandler(__DIR__.'/slavedriver.log'));

$slavedriver->setLogger($logger);

或者使用自定义日志级别(例如,将ErrorExitCode日志级别重写为alert

$logLevels = new \deploydog\Slavedriver\LogLevels();
$logLevels->setErrorExitCode(\Psr\Log\LogLevel::ALERT);

$slavedriver->setLogger($logger, $logLevels);

异常

Slavedriver抛出的所有异常都扩展了基本Slavedriver异常deploydog\Slavedriver\Exception\Slavedriver,它扩展了基本PHP异常\Exception。不同的Slavedriver异常会因不同原因而抛出,例如InvalidJobInvalidSlavedriverConfig。请检查异常目录以获取可能选项。