Background

Job Plugins are designed to generally run via cron, and so do not follow standard MVC patterns. However, since Plugins may be polymorphic, they may implement other functionality that does.

Entry Point Model

Job Plugins implement an Entry Point Model, defined in the Plugin's src/Lib/Jobs directory, that implements a run() function with the following signature:

public function run(
  \App\Model\Table\JobsTable $JobsTable,
  \App\Model\Table\JobsTable $JobHistoryRecordsTable,
  \App\Model\Entity\Job $job, 
  array $parameters
)

Note there is no defined return value. The entry point function is expected to update the Job record with status as it progresses. If the Job Plugin exits unexpectedly, the Job will automatically be placed in Failed status.

Parameter Formats

The Entry Point Model must also implement a parameterFormat() function that returns an array of parameters accepted by the plugin. This configuration is used to validate parameters passed to the Plugin when new Jobs are registered. Each entry in the array has a key of the parameter name and a value of an array with the following keys:

  1. type: One of boolint, select, or string.
  2. required: Boolean indicating whether or not this parameter is required
  3. choices: An array of permitted values for the parameter (when type is select)
  4. help: Help text for the parameter

Database Access

Registry Job Command can run multiple Jobs in parallel, and accomplishes this by forking the current process. As a result, care must be taken when accessing database connections, or else a child process terminating may cause database connections to close for other processes. When launching a new Job (via a child process) Job Command will create a new database connection that should be used by the Job plugin. This is accomplished by setting the connection on the table to be queried.

This requirement may be removed in a future release. (CFM-253)

Example

// $plugin/src/config/plugin.json

{
  "types": {
    "job": [
      "WidgetJob"
    ]
  }
}

// $plugin/src/Lib/Jobs/WidgetJob.php

use Cake\Datasource\ConnectionManager;
use Cake\ORM\TableRegistry;

class WidgetJob {
  public function parameterFormat(): array {
    return [
      'size' => [
        'type'     => 'integer',
        'required' => true,
        'help'     => "How big the widgets should be, in centimeters"
      ]
    ];
  }

  public function run(
    \App\Model\Table\JobsTable $JobsTable,
    \App\Model\Table\JobsTable $JobHistoryRecordsTable,
    \App\Model\Entity\Job $job, 
    array $parameters
  ) {
    // $JobsTable and $JobHistoryRecordsTable will already be set to use the correct connection,
    // but other tables need to be reconfigured to use the "plugin" connection
    
    $cxn = ConnectionManager::get('plugin')

    $Widgets = TableRegistry::getTableLocator->get('Widgets');
    $Widgets->setConnection($cxn);
    
    $JobsTable->start(job: $job, summary: "Starting");

    // Do some work, set the percent complete, record some history, etc

    $JobsTable->finish(job: $job, summary: "All done!");
  }
}

See Also

  • No labels