silverstripe / queuedjobs

此包已被 弃用 且不再维护。作者建议使用 symbiote/silverstripe-queuedjobs 包。

一个用于定义和按队列方式运行后台作业的框架

安装 145,975

依赖者: 8

建议者: 4

安全: 0

星标: 53

关注者: 9

分支: 72

类型:silverstripe-vendormodule


README

Build Status Scrutinizer SilverStripe supported module

概述

队列作业模块为 SilverStripe 开发者提供了一种框架,用于定义应作为后台任务运行的长时间运行过程。这种异步处理允许用户在允许时继续使用系统,同时长时间运行的任务继续进行。它还允许开发者在将来设置这些过程。

模块包含以下内容

  • 一个 CMS 部分,用于查看当前运行或计划中的作业列表。
  • 一个用于定义您自己的作业的抽象骨架类。
  • 一个作为 cronjob 执行的作业,用于收集和执行作业。
  • 一个预先配置的作业,用于清理 QueuedJobDescriptor 数据库表。

安装

composer require symbiote/silverstripe-queuedjobs

现在设置一个 cron 作业

*/1 * * * * /path/to/silverstripe/vendor/bin/sake dev/tasks/ProcessJobQueueTask
  • 要安排在未来的某个时间点执行作业,请通过调用 queueJob 传递一个日期。以下命令将在现在起1天后运行发布作业。
use SilverStripe\ORM\FieldType\DBDatetime;
use Symbiote\QueuedJobs\Services\QueuedJobService;

$publish = new PublishItemsJob(21);
QueuedJobService::singleton()
    ->queueJob($publish, DBDatetime::create()->setValue(DBDatetime::now()->getTimestamp() + 86400)->Rfc2822());

使用 Doorman 运行作业

Doorman 默认包含在内,允许异步任务处理。

这需要您在一个基于 Unix 的系统上运行,或者在某些环境模拟器(如 cygwin)中运行。

为了启用此功能,配置 ProcessJobQueueTask 以使用此后端。

在您的 YML 设置中设置以下内容

---
Name: localproject
After: '#queuedjobsettings'
---
SilverStripe\Core\Injector\Injector:
  Symbiote\QueuedJobs\Services\QueuedJobService:
    properties:
      queueRunner: %$DoormanRunner

使用 Gearman 运行作业

---
Name: localproject
After: '#queuedjobsettings'
---
SilverStripe\Core\Injector\Injector:
  QueueHandler:
    class: Symbiote\QueuedJobs\Services\GearmanQueueHandler
  • 使用 php gearman/gearman_runner.php 在您的 SS 根目录下运行 gearman 工作者

这将导致所有队列作业通过 gearman 工作者(src/workers/JobWorker.php)立即触发,除了那些设置了 StartAfter 日期的作业,这些作业仍然需要上面提到的 cron 设置

使用 QueuedJob::IMMEDIATE 作业

通过使用基于文件的提醒系统,队列作业可以立即执行(而不是受 cron 的 1 分钟间隔限制)。这依赖于类似 inotifywait 的东西来监视一个文件夹(默认为 SILVERSTRIPE_CACHE_DIR/queuedjobs)并触发 ProcessJobQueueTask,就像上面一样,但是通过传递 job=$filename 作为参数。在 queuedjobs/scripts 中有一个示例脚本,它将运行 inotifywait,然后在新的作业准备好运行时调用 ProcessJobQueueTask。

注意 - 如果您没有运行此脚本,请确保设置 QueuedJobService::$use_shutdown_function = true;,以便立即模式作业不会延迟。通过将其设置为 true,立即作业将在 PHP 脚本结束时,在请求完成后执行。

默认作业

某些工作应该始终处于运行状态或排队运行状态,例如数据刷新或周期性清理工作,我们称这些为默认工作。默认工作在每个工作队列过程结束时进行检查,使用工作类型和过滤器中的任何字段来创建一个SQL查询,例如:

ArbitraryName:
  type: 'ScheduledExternalImportJob'
  filter:
    JobTitle: 'Scheduled import from Services'

将变为:

QueuedJobDescriptor::get()->filter([
  'type' => 'ScheduledExternalImportJob',
  'JobTitle' => 'Scheduled import from Services'
]);

该查询将检查是否有至少1个符合过滤器条件的健康(新、运行、等待或暂停)的工作。如果没有且在yml配置中将recreate设置为true,我们将使用构造数组作为参数传递给新的工作对象,例如:

ArbitraryName:
  type: 'ScheduledExternalImportJob'
  filter:
    JobTitle: 'Scheduled import from Services'
  recreate: 1
  construct:
    repeat: 300
    contentItem: 100
      target: 157

如果上述工作缺失,它将被重新创建为:

Injector::inst()->createWithArgs(ScheduledExternalImportJob::class, $construct[])

暂停默认工作

如果您需要停止默认工作触发警报和重新创建,请在CMS中将现有工作副本设置为暂停。

YML配置

默认工作在yml配置中定义,以下示例涵盖了选项和预期值。

SilverStripe\Core\Injector\Injector:
  Symbiote\QueuedJobs\Services\QueuedJobService:
    properties:
      defaultJobs:
        # This key is used as the title for error logs and alert emails
        ArbitraryName:
          # The job type should be the class name of a job REQUIRED
          type: 'ScheduledExternalImportJob'
          # This plus the job type is used to create the SQL query REQUIRED
          filter:
            # 1 or more Fieldname: 'value' sets that will be queried on REQUIRED
            #  These can be valid ORM filter
            JobTitle: 'Scheduled import from Services'
          # Parameters set on the recreated object OPTIONAL
          construct:
            # 1 or more Fieldname: 'value' sets be passed to the constructor REQUIRED
            # If your constructor needs none, put something arbitrary
            repeat: 300
            title: 'Scheduled import from Services'
          # A date/time format string for the job's StartAfter field REQUIRED
          # The shown example generates strings like "2020-02-27 01:00:00"
          startDateFormat: 'Y-m-d H:i:s'
          # A string acceptable to PHP's date() function for the job's StartAfter field REQUIRED
          startTimeString: 'tomorrow 01:00'
          # Sets whether the job will be recreated or not OPTIONAL
          recreate: 1
          # Set the email address to send the alert to if not set site admin email is used OPTIONAL
          email: '[email protected]'
        # Minimal implementation will send alerts but not recreate
        AnotherTitle:
          type: 'AJob'
          filter:
            JobTitle: 'A job'

配置CleanupJob

默认情况下,CleanupJob被禁用。要启用它,请在您的YML中设置以下内容:

Symbiote\QueuedJobs\Jobs\CleanupJob:
  is_enabled: true

您需要在UI中手动触发第一次运行。之后,CleanupJob每天运行一次。

您可以将此工作配置为根据工作数量或工作年龄进行清理。这是通过cleanup_method设置配置的 - 当前有效值为"age"(默认)和"number"。每种方法都将有一个与其相关联的值 - 这是一个整数,通过cleanup_value设置。对于"age",它将转换为天数;对于"number",它是按LastEdited排序的最小记录数。默认值为30,因为我们预计是按天数。

您可以选择要清理哪些JobStatuses。默认设置是清理"Broken"和"Complete"工作。所有其他状态都可以通过cleanup_statuses进行配置。您还可以定义query_limit来限制清理工作查询/删除的行数(默认为100k)。

默认配置如下所示:

Symbiote\QueuedJobs\Jobs\CleanupJob:
  is_enabled: false
  query_limit: 100000
  cleanup_method: "age"
  cleanup_value: 30
  cleanup_statuses:
    - Broken
    - Complete

工作队列暂停设置

可以启用一个设置,允许暂停排队的工作处理。要启用它,请将以下代码添加到您的配置YAML文件中:

Symbiote\QueuedJobs\Services\QueuedJobService:
  lock_file_enabled: true
  lock_file_path: '/shared-folder-path'

队列设置选项卡将出现在CMS设置中,并且将有一个选项来暂停排队的工作处理。如果启用,则不会启动新的工作,但是已经运行的工作将被允许完成。这对于计划中的停机时间非常有用,例如与第三方服务维护或数据库恢复/备份操作相关的队列工作。

请注意,此维护锁定状态存储在文件中。这是故意不使用数据库作为存储,因为某些维护操作期间它可能不可用。请确保lock_file_path指向共享驱动器上的文件夹,如果您正在运行具有多个实例的服务器。

文件锁定的一个好处是在关键故障(例如:站点崩溃且CMS不可用)的情况下,您仍然可以访问文件系统并手动更改文件锁定。这为您在运行中的工作导致问题的情况下提供了额外的灾难恢复选项。

健康检查

作业通过步骤跟踪其执行情况 - 作业运行时,会增加已运行的“步骤”数量。定期检查作业以确保其正常运行。这确保了在健康检查之间,作业的步骤计数总是增加。默认情况下,当工作器开始运行队列时,会执行健康检查。

在多工作器环境中,如果健康检查过于频繁,可能会引起问题。您可以使用以下配置禁用自动健康检查:

Symbiote\QueuedJobs\Services\QueuedJobService:
  disable_health_check: true

除了配置设置之外,还有一个可以与cron一起使用来确保检测到不健康作业的任务。

*/5 * * * * /path/to/silverstripe/vendor/bin/sake dev/tasks/CheckJobHealthTask

特殊作业变量

了解应在使用作业实现时使用的特殊变量是很重要的。

  • totalSteps(整数)- 默认为 0,映射到数据库中的 TotalSteps 列,仅作信息用
  • currentStep(整数)- 默认为 0,映射到数据库中的 StepsProcessed 列,队列运行者使用此值来判断作业是否停滞
  • isComplete(布尔值)- 默认为 false,与数据库中的 JobStatus 列相关,队列运行者使用此值来判断作业是否完成

有关 JobJobDescriptor 之间映射的更多详细信息,请参阅 copyJobToDescriptor

总步骤数

表示完成作业所需的总步骤数。

  • 此变量应设置为作业执行期间预期的步骤数
  • 需要在作业的 setup() 函数中完成此操作,该值之后不应更改
  • 此变量不被队列运行者使用,仅用于指示所需的步骤数(仅作信息用)
  • 建议不要在作业的 process() 函数中使用此变量,而是根据作业数据(是否有剩余项目需要处理)来确定作业是否完成

当前步骤

表示已处理的步骤数。

  • 每次成功完成作业步骤时,您的作业应增加此变量
  • 队列运行者将读取此变量以确定作业是否停滞
  • 建议每次增加此变量时都退出 process() 函数
  • 这允许队列运行者通过将作业进度保存到存储在数据库中的作业描述符来创建检查点

是否完成

表示作业状态(完成或未完成)。

  • 将此变量设置为 true 将向队列运行者发送信号,以将作业标记为成功完成
  • 您的作业应仅将此变量设置为 true 一次

示例

此示例说明了如何在作业实现中使用每个特殊变量。

<?php

namespace App\Jobs;

use Symbiote\QueuedJobs\Services\AbstractQueuedJob;

/**
 * Class MyJob
 *
 * @property array $items
 * @property array $remaining
 */
class MyJob extends AbstractQueuedJob
{
    public function hydrate(array $items): void
    {
        $this->items = $items;
    }

    /**
     * @return string
     */
    public function getTitle(): string
    {
        return 'My awesome job';
    }

    public function setup(): void
    {
        $this->remaining = $this->items;

        // Set the total steps to the number of items we want to process
        $this->totalSteps = count($this->items);
    }

    public function process(): void
    {
        $remaining = $this->remaining;

        // check for trivial case
        if (count($remaining) === 0) {
            $this->isComplete = true;

            return;
        }

        $item = array_shift($remaining);

        // code that will process your item goes here
        $this->doSomethingWithTheItem($item);

        $this->remaining = $remaining;

        // Updating current step tells the Queue runner that the job is progressing
        $this->currentStep += 1;

        // check for job completion
        if (count($remaining) > 0) {
            // Note that we do not process more than one item at a time
            // this makes the Queue runner save the job progress into DB
            // in case something goes wrong the job will be resumed from the last checkpoint
            return;
        }

        // Queue runner will mark this job as finished
        $this->isComplete = true;
    }
}

故障排除

为了确保作业正常运行,您首先可以尝试在队列框架之外直接执行作业 - 这可以通过手动调用 setup()process() 方法来实现。如果在这种情况下运行良好,请尝试让 getJobType() 返回 QueuedJob::IMMEDIATE 以实现立即执行,而不需要持久化或通过 crontab 执行。如果这样操作可行,接下来请确保您的 crontab 作业配置正确并正在执行。

如果正在定义自己的作业类,请注意,当作业在队列中启动时,作业类是在没有参数传递的情况下构建的 (不传递参数);这意味着如果您接受构造函数参数,您 必须 在使用它们之前检测它们是否存在。有关更多信息,请参阅 此问题此维基页面

如果您正在定义自己的作业,请确保您遵循 PSR 规范,即使用 "YourVendor" 而不是 "SilverStripe"。

请确保已配置通知,以便您能够获取停滞或损坏的作业的更新。您可以在配置中设置以下通知电子邮件地址:

SilverStripe\Control\Email\Email:
  queued_job_admin_email: [email protected]

文档

显示作业数据

如果您需要通过 CMS 轻松访问额外的作业数据以进行调试,请通过包含以下配置来启用 show_job_data 选项。

Symbiote\QueuedJobs\DataObjects\QueuedJobDescriptor:
  show_job_data: true

这将向作业描述符编辑表单添加作业数据和消息原始标签。显示的信息为只读。

贡献

翻译

自然语言字符串的翻译通过第三方翻译接口 transifex.com 进行管理。新添加的字符串将定期上传到那里进行翻译,任何新的翻译都将合并到项目源代码中。

请使用 https://www.transifex.com/projects/p/silverstripe-queuedjobs 贡献翻译,而不是发送包含 YAML 文件的拉取请求。