arbit / periodic
Periodic 是一个经过完全单元测试的 PHP 基础任务运行器。它旨在为管理您的 Web 应用程序中的各种重复性任务和事件提供基本实现。
Requires
- arbit/xml: dev-master
This package is auto-updated.
Last update: 2021-04-07 16:46:42 UTC
README
Periodic 是一个经过完全单元测试的 PHP 基础任务运行器。它旨在为管理您的 Web 应用程序中的各种重复性任务和事件提供基本实现。它考虑到所有不同类型的 Web 托管环境而设计。它能够在大多数共享托管系统以及根服务器上运行。
动机
我们需要为目前正在进行的多个项目创建某种重复性任务管理系统。我们首先开始开发一种 CronjobIterator,它可以解析 cron 定义(您可能从著名的 vixie-cron 守护程序中知道这种定义)并提供一个与该定义匹配的时间戳的可迭代列表。vcron 定义语法似乎是最直观和最广泛使用的语法来描述重复事件,因此我们选择了它。
我们为其编写了一份设计文档,并开始讨论它。我们试图创建一个模块化和灵活的系统,以满足多个项目的需求。
构建/测试
要构建项目,请输入以下命令
git submodule init git submodule update composer.phar install ant
前两个命令仅需要在第一次构建时使用。ant
命令应该运行测试和所有验证。
软件设计
需求
Periodic 的需求是执行在指定时间或时间间隔内配置的任务列表。
任务的执行可以通过以下三种方式之一触发
- 通过守护程序,仅监督任务执行
- 通过 cronjob,它不时检查是否有任何要运行的任务
- 使用网站,它触发所有打开的任务
不同的执行模型是必要的,以支持不同的使用配置文件:在纯构建机器上运行、在专用服务器上运行或在共享托管上运行。
任务本身通过 cron 表中的名称指定,并使用 XML 文件进行配置。XML 文件包含要执行的一组命令。可用的命令以通用的 shell 命令和文件操作开始,并应可扩展为应用程序相关的命令。每个命令都应该能够接收一组任意的配置值。
设计
此组件的设计分为四个主要部分:执行、crontab、任务规范和命令本身。
执行
执行器(一个被调用的脚本或守护程序)必须执行自上次调用以来挂起的所有任务。不得执行多次。
在执行任何任务期间,执行器应保持锁定,以确保没有任务并行运行多次,这可能导致冲突或死锁。
如果执行器崩溃,它可能不会释放其锁定。应在配置中指定多久后锁定可以自动释放,或者是否应由用户手动释放。
定时表
crontab遵循cron表,通常从Unix cron实现中了解,除非命令被任务名称替代。一个简单的cron表,每15分钟调度一次“periodic-test-task”任务,可能看起来像
*/15 * * * * group:periodic-test-task
执行器解析cron表,计算自上次调用以来的待办任务,并按顺序执行它们。
一个组中的任务不能由执行器并行执行。任务组是可选的,并附加到任务名称前,用冒号分隔。
任务规范
任务使用XML文件指定,该文件位于执行器指定的目录中,名称为$task.xml,其中$task是cron表中给出的任务名称。
XML文件基本上应该看起来像
<?xml version="1.0"?> <task> <config> <reScheduleTime>92384032</> <timeout>92384032</> </config> <command type="shell"> <!-- ... --> </command> <command type="vcsWrapperUpdate"> <!-- ... --> </command> <!-- ... --> </task>
命令类型是一个必选属性,指定了命令的类型,它应由执行器实例化。
每个任务可以包含一组配置指令,用于定义任务在错误或其他特殊返回状态下的行为。命令的可能返回状态包括
重新安排
任务应重新安排,例如,因为资源暂时不可用。
中止
命令可能返回“中止”,表示任务中进一步命令的执行可能不合理。
失败
命令执行失败,任务应通过记录错误来表示这一点。
成功
命令已成功执行,其他命令的进一步执行应没有问题。
每个命令节点可以包含任意数量的XML元素,以配置给定命令的执行。
命令
所有命令类都继承自Command,它指定了构造函数,该构造函数接受来自任务规范文件的命令XML子树作为其配置,以及一个execute()方法
abstract class Command { abstract public function __construct( arbitXmlNode $configuration ); /** * Execute command and return false on failure. * * @return status */ abstract public function execute(); }
所有命令必须在CommandRegistry下以与任务规范中的类型属性相关的名称注册,并由执行器实例化。
全局关注点
有一些全局关注点是Periodic的所有部分共有的,并且可能还需要与使用Periodic的应用程序集成。
日志记录
在后台长时间运行的脚本或定期在后台执行的脚本需要日志记录以保持可调试性和可维护性。
Periodic应提供日志记录器接口,该接口可以实施,并且可以将实例传递给执行器,以便可以对任务和命令执行进行记录。基本基于文件的日志记录机制可能被实现为默认的日志记录机制。
日志记录接口可能是以下简单形式
interface Logger { const INFO = 1; const WARNING = 2; const ERROR = 4; public function log( (toString) $message, $severity = self::INFO ); public function setTask( Task $task ); public function setCommand( Command $command ); }