Initial worker definition. Needs a jobs table to be created
This commit is contained in:
13
composer.json
Normal file
13
composer.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "avsdev/sprinkle-worker",
|
||||
"type": "userfrosting-worker",
|
||||
"description": "A sprinkle to add a worker thread.",
|
||||
"autoload": {
|
||||
"files" : [
|
||||
"defines.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"UserFrosting\\Sprinkle\\Worker\\": "src/"
|
||||
}
|
||||
}
|
||||
}
|
||||
13
defines.php
Normal file
13
defines.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* AVSDev UF Worker (https://avsdev.uk)
|
||||
*
|
||||
* @link https://git.avsdev.uk/avsdev/sprinkle-worker
|
||||
* @license https://git.avsdev.uk/avsdev/sprinkle-worker/blob/master/LICENSE.md (LGPL-3.0 License)
|
||||
*/
|
||||
|
||||
namespace UserFrosting;
|
||||
|
||||
// Relative path from within sprinkle directory
|
||||
define('UserFrosting\JOBS_DIR', SRC_DIR_NAME . DS . 'Jobs');
|
||||
45
src/Bakery/WorkerListCommand.php
Normal file
45
src/Bakery/WorkerListCommand.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* AVSDev UF Worker (https://avsdev.uk)
|
||||
*
|
||||
* @link https://git.avsdev.uk/avsdev/sprinkle-worker
|
||||
* @license https://git.avsdev.uk/avsdev/sprinkle-worker/blob/master/LICENSE.md (LGPL-3.0 License)
|
||||
*/
|
||||
|
||||
namespace UserFrosting\Sprinkle\Worker\Bakery;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use UserFrosting\System\Bakery\BaseCommand;
|
||||
|
||||
/**
|
||||
* worker Bakery Command
|
||||
* List potential jobs.
|
||||
*
|
||||
* @author Craig Williams (https://avsdev.uk)
|
||||
*/
|
||||
class WorkerListCommand extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('worker:list')
|
||||
->setDescription('List all potential jobs')
|
||||
->setHelp('This command returns a list of potential worker jobs that can be queued to be run by the worker.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->io->title('Available Jobs List');
|
||||
$jobs = $this->ci->worker->getAvailableJobDefinitions();
|
||||
$this->io->table(['Sprinkle', 'Name', 'Namespace'], $jobs);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
46
src/Bakery/WorkerRunCommand.php
Normal file
46
src/Bakery/WorkerRunCommand.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* AVSDev UF Worker (https://avsdev.uk)
|
||||
*
|
||||
* @link https://git.avsdev.uk/avsdev/sprinkle-worker
|
||||
* @license https://git.avsdev.uk/avsdev/sprinkle-worker/blob/master/LICENSE.md (LGPL-3.0 License)
|
||||
*/
|
||||
|
||||
namespace UserFrosting\Sprinkle\Worker\Bakery;
|
||||
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use UserFrosting\System\Bakery\BaseCommand;
|
||||
|
||||
/**
|
||||
* worker:run Bakery Command
|
||||
* Run a worker thread.
|
||||
*
|
||||
* @author Craig Williams (https://avsdev.uk)
|
||||
*/
|
||||
class WorkerRunCommand extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('worker:run')
|
||||
->setDescription('Run a worker loop')
|
||||
->setHelp('This command runs a the workers job loop. The worker will not return until SIGTERM is sent.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$worker = $this->ci->worker;
|
||||
|
||||
$worker->run($this->io);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
35
src/Jobs/JobBase.php
Normal file
35
src/Jobs/JobBase.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* AVSDev UF Worker (https://avsdev.uk)
|
||||
*
|
||||
* @link https://git.avsdev.uk/avsdev/sprinkle-worker
|
||||
* @license https://git.avsdev.uk/avsdev/sprinkle-worker/blob/master/LICENSE.md (LGPL-3.0 License)
|
||||
*/
|
||||
|
||||
namespace UserFrosting\Sprinkle\Worker\Jobs;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Job Base Class
|
||||
*
|
||||
* @author Craig Williams (https://avsdev.uk)
|
||||
*/
|
||||
abstract class JobBase implements JobInterface
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $ci;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param ContainerInterface $ci
|
||||
*/
|
||||
public function __construct(ContainerInterface $ci)
|
||||
{
|
||||
$this->ci = $ci;
|
||||
}
|
||||
}
|
||||
31
src/Jobs/JobInterface.php
Normal file
31
src/Jobs/JobInterface.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* AVSDev UF Worker (https://avsdev.uk)
|
||||
*
|
||||
* @link https://git.avsdev.uk/avsdev/sprinkle-worker
|
||||
* @license https://git.avsdev.uk/avsdev/sprinkle-worker/blob/master/LICENSE.md (LGPL-3.0 License)
|
||||
*/
|
||||
|
||||
namespace UserFrosting\Sprinkle\Worker\Jobs;
|
||||
|
||||
|
||||
/**
|
||||
* All jobs must implement this interface.
|
||||
*
|
||||
* @author Craig Williams (https://avsdev.uk)
|
||||
*/
|
||||
interface JobInterface
|
||||
{
|
||||
/**
|
||||
* Function used to specify what the job does.
|
||||
*
|
||||
* Add parameters with default values if needed.
|
||||
*/
|
||||
public function run();
|
||||
|
||||
/**
|
||||
* Terminate the current job
|
||||
*/
|
||||
public function terminate();
|
||||
}
|
||||
42
src/ServicesProvider/ServicesProvider.php
Normal file
42
src/ServicesProvider/ServicesProvider.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* AVSDev UF Worker (https://avsdev.uk)
|
||||
*
|
||||
* @link https://git.avsdev.uk/avsdev/sprinkle-worker
|
||||
* @license https://git.avsdev.uk/avsdev/sprinkle-worker/blob/master/LICENSE.md (LGPL-3.0 License)
|
||||
*/
|
||||
|
||||
namespace UserFrosting\Sprinkle\Worker\ServicesProvider;
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use UserFrosting\Sprinkle\Worker\Worker\Worker;
|
||||
use UserFrosting\Sprinkle\Core\ServicesProvider\BaseServicesProvider;
|
||||
|
||||
/**
|
||||
* Worker services provider.
|
||||
*
|
||||
* Registers core services for the Worker sprinkle.
|
||||
*
|
||||
* @author Craig Williams (https://avsdev.uk)
|
||||
*/
|
||||
class ServicesProvider
|
||||
{
|
||||
/**
|
||||
* Register Worker's services.
|
||||
*
|
||||
* @param ContainerInterface $container A DI container implementing ArrayAccess and psr-container.
|
||||
*/
|
||||
public function register(ContainerInterface $container)
|
||||
{
|
||||
/*
|
||||
* Return an instance of the worker
|
||||
*
|
||||
* @return \UserFrosting\Sprinkle\Worker\Worker\Worker
|
||||
*/
|
||||
$container['worker'] = function ($c) {
|
||||
return new Worker($c);
|
||||
};
|
||||
}
|
||||
}
|
||||
40
src/Worker.php
Normal file
40
src/Worker.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* AVSDev UF Worker (https://avsdev.uk)
|
||||
*
|
||||
* @link https://git.avsdev.uk/avsdev/sprinkle-worker
|
||||
* @license https://git.avsdev.uk/avsdev/sprinkle-worker/blob/master/LICENSE.md (LGPL-3.0 License)
|
||||
*/
|
||||
|
||||
namespace UserFrosting\Sprinkle\Worker;
|
||||
|
||||
use UserFrosting\System\Sprinkle\Sprinkle;
|
||||
|
||||
/**
|
||||
* Bootstrapper class for the 'worker' sprinkle.
|
||||
*
|
||||
* @author Craig Williams (https://avsdev.uk)
|
||||
*/
|
||||
class Worker extends Sprinkle
|
||||
{
|
||||
/**
|
||||
* Set static references to DI container in necessary classes.
|
||||
*/
|
||||
public function onSprinklesInitialized()
|
||||
{
|
||||
$this->registerStreams();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register worker sprinkle locator streams.
|
||||
*/
|
||||
protected function registerStreams()
|
||||
{
|
||||
/** @var \UserFrosting\UniformResourceLocator\ResourceLocator $locator */
|
||||
$locator = $this->ci->locator;
|
||||
|
||||
// Register jobs sprinkle class streams
|
||||
$locator->registerStream('jobs', '', \UserFrosting\JOBS_DIR);
|
||||
}
|
||||
}
|
||||
147
src/Worker/Worker.php
Normal file
147
src/Worker/Worker.php
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* AVSDev UF Worker (https://avsdev.uk)
|
||||
*
|
||||
* @link https://git.avsdev.uk/avsdev/sprinkle-worker
|
||||
* @license https://git.avsdev.uk/avsdev/sprinkle-worker/blob/master/LICENSE.md (LGPL-3.0 License)
|
||||
*/
|
||||
|
||||
namespace UserFrosting\Sprinkle\Worker\Worker;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use UserFrosting\UniformResourceLocator\Resource as ResourceInstance;
|
||||
|
||||
/**
|
||||
* Worker Class.
|
||||
*
|
||||
* Finds all job classes across sprinkles
|
||||
*
|
||||
* @author Craig Williams (https://avsdev.uk)
|
||||
*/
|
||||
class Worker
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $ci;
|
||||
|
||||
/**
|
||||
* @var string The resource locator scheme
|
||||
*/
|
||||
protected $scheme = 'jobs://';
|
||||
|
||||
/**
|
||||
* @var object The currently processing job
|
||||
*/
|
||||
protected $currentJob = null;
|
||||
|
||||
/**
|
||||
* Class Constructor.
|
||||
*
|
||||
* @param ContainerInterface $ci
|
||||
*/
|
||||
public function __construct(ContainerInterface $ci)
|
||||
{
|
||||
$this->ci = $ci;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop all the available sprinkles and return a list of their jobs.
|
||||
*
|
||||
* @return array An array of all the task classes found for every sprinkle
|
||||
*/
|
||||
public function getAvailableJobDefinitions()
|
||||
{
|
||||
$tasks = $this->ci->locator->listResources($this->scheme, false, false);
|
||||
|
||||
return $this->loadAvailableJobDefinitions($tasks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process jobs Resource into info.
|
||||
*
|
||||
* @param array $taskFiles List of jobs files
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function loadAvailableJobDefinitions(array $jobFiles)
|
||||
{
|
||||
$jobs = [];
|
||||
|
||||
foreach ($jobFiles as $jobFile) {
|
||||
$job = $this->getJobDefinition($jobFile);
|
||||
if ($job) {
|
||||
$jobs[] = $job;
|
||||
}
|
||||
}
|
||||
|
||||
return $jobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of job details including the class name and the sprinkle name.
|
||||
*
|
||||
* @param ResourceInstance $file The job file
|
||||
*
|
||||
* @return array The details about a job file [name, class, sprinkle]
|
||||
*/
|
||||
protected function getJobDefinition(ResourceInstance $file)
|
||||
{
|
||||
// Format the sprinkle name for the namespace
|
||||
$sprinkleName = $file->getLocation()->getName();
|
||||
$sprinkleName = Str::studly($sprinkleName);
|
||||
|
||||
// Getting base path, name and class name
|
||||
$basePath = str_replace($file->getBasename(), '', $file->getBasePath());
|
||||
$name = $basePath . $file->getFilename();
|
||||
$className = str_replace('/', '\\', $basePath) . $file->getFilename();
|
||||
$classPath = "\\UserFrosting\\Sprinkle\\$sprinkleName\\Worker\\Jobs\\$className";
|
||||
|
||||
if ($className == "JobInterface" || $className == "JobBase") {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Build the class name and namespace
|
||||
return [
|
||||
'sprinkle' => $sprinkleName,
|
||||
'name' => $name,
|
||||
'class' => $classPath,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Runs the worker loop, procssing queued jobs.
|
||||
*/
|
||||
public function run($io)
|
||||
{
|
||||
pcntl_async_signals(TRUE);
|
||||
|
||||
pcntl_signal(SIGINT, array($this, "handleTerm"));
|
||||
pcntl_signal(SIGQUIT, array($this, "handleTerm"));
|
||||
pcntl_signal(SIGTERM, array($this, "handleTerm"));
|
||||
|
||||
while(true) {
|
||||
// TODO: find jobs in the database
|
||||
|
||||
try {
|
||||
// Run the job using call_user_func_array
|
||||
} catch(Exception $ex) {
|
||||
$io->error('An exception occurred attempting to run a job');
|
||||
var_dump($ex);
|
||||
} finally {
|
||||
$this->currentJob = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function handleTerm($signo, $siginfo) {
|
||||
if ($this->currentJob) {
|
||||
$this->currentJob->terminate();
|
||||
$this->currentJob = null;
|
||||
}
|
||||
exit;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user