deploy-dog / slavedriver
基于PHP的cron作业执行器。管理、监控、记录和响应预定任务中的问题。
Requires
- php: ^7.0
- cocur/slugify: *
- dragonmantank/cron-expression: ^2.0.0
- malkusch/lock: *
- phossa2/event: ^2.1.0
- psr/log: ^1.0
- psr/simple-cache: ^1.0
Requires (Dev)
- phpunit/phpunit: ^6.1 || ^5.7
Suggests
- matthiasmullie/scrapbook: Caching adapters compatible with Slavedriver.
- monolog/monolog: Compatible loggers.
README
基于PHP的cron作业执行器。管理、监控、记录和响应预定任务中的问题。由deploy.dog团队创建,最初用于内部使用,但经过修改和发布,供其他人享受。由deploy.dog创建,最初用于内部使用,但发布供其他人享受。
要求
- 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异常会因不同原因而抛出,例如InvalidJob
和InvalidSlavedriverConfig
。请检查异常目录以获取可能选项。