Skip to content
This repository has been archived by the owner on Mar 23, 2023. It is now read-only.

Add ability to include plugins on Jobs #37

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 62 additions & 9 deletions lib/Resque/Job.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ public static function create($queue, $class, $args = null, $monitor = false)
} else {
$id = md5(uniqid('', true));
}

if (empty($args)) {
$args = [];
}

Resque::push($queue, array(
'class' => $class,
'args' => array($args),
Expand Down Expand Up @@ -145,11 +150,13 @@ public function getArguments()
return $this->payload['args'][0];
}

/**
* Get the instantiated object for this job that will be performing work.
*
* @return object Instance of the object that this job belongs to.
*/
/**
* Get the instantiated object for this job that will be performing work.
*
* @return object Instance of the object that this job belongs to.
*
* @throws \Resque_Exception
*/
public function getInstance()
{
if (!is_null($this->instance)) {
Expand Down Expand Up @@ -189,20 +196,30 @@ public function getInstance()
public function perform()
{
$instance = $this->getInstance();

$hooks = [
'before' => $this->beforeHooks(),
'around' => $this->aroundHooks(),
'after' => $this->afterHooks()
];

try {
Resque_Event::trigger('beforePerform', $this);

if(method_exists($instance, 'setUp')) {
$instance->setUp();
$hooks['before'][] = 'setUp';
}

$instance->perform();

if(method_exists($instance, 'tearDown')) {
$instance->tearDown();
array_unshift($hooks['after'], 'tearDown');
}

$performer = new Resque_Job_Performer($instance, $this->getArguments(), $hooks);

$performer->perform();

Resque_Event::trigger('afterPerform', $this);

}
// beforePerform/setUp have said don't perform this job. Return.
catch(Resque_Job_DontPerform $e) {
Expand All @@ -212,6 +229,42 @@ public function perform()
return true;
}

/**
* beforeHooks
*
* @return array
*
* @throws \Resque_Exception
*/
public function beforeHooks()
{
return Resque_Plugin::beforeHooks($this->getInstance());
}

/**
* afterHooks
*
* @return array
*
* @throws \Resque_Exception
*/
public function afterHooks()
{
return Resque_Plugin::afterHooks($this->getInstance());
}

/**
* aroundHooks
*
* @return array
*
* @throws \Resque_Exception
*/
public function aroundHooks()
{
return Resque_Plugin::aroundHooks($this->getInstance());
}

/**
* Mark the current job as having failed.
*
Expand Down
159 changes: 159 additions & 0 deletions lib/Resque/Job/Performer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<?php

/**
* Resque job performer.
*
* @package Resque/Job
* @author Protec Innovations <[email protected]>
* @license http://www.opensource.org/licenses/mit-license.php
*/
class Resque_Job_Performer
{
const HOOKS_AFTER = 'after';
const HOOKS_AROUND = 'around';
const HOOKS_BEFORE = 'before';

/**
* @var object $job
*/
private $job;

/**
* @var array $args
*/
private $args;

/**
* @var array $hooks
*/
private $hooks;

/**
* @var bool $performed
*/
private $performed = false;

/**
* Resque_Job_Performer constructor.
*
* @param object $job
* @param array $args
* @param array $hooks
*/
public function __construct($job, array $args, array $hooks)
{
$this->job = $job;
$this->args = $args;
$this->hooks = $hooks;
}

/**
* perform
*
* @return bool
*/
public function perform()
{
$this->callBeforeHooks();

$this->executeJob();

$this->callHooks(self::HOOKS_AFTER);

return $this->performed;
}

/**
* callBeforeHooks
*
*/
protected function callBeforeHooks()
{
$this->callHooks(self::HOOKS_BEFORE);
}

/**
* callHooks
*
* @param string $hook_type
*/
protected function callHooks($hook_type)
{
foreach ($this->hooks[$hook_type] as $hook) {
$this->performHook($hook);
}
}

/**
* performHook
*
* @param string $hook
*/
protected function performHook($hook)
{
call_user_func_array([$this->job, $hook], $this->args);
}

/**
* executeJob
*
*/
protected function executeJob()
{
if (empty($this->hooks[self::HOOKS_AROUND])) {
$this->performJob();
} else {
$this->callAroundHooks();
}
}

/**
* callAroundHooks
*
*/
protected function callAroundHooks()
{
$hooks = $this->nestedAroundHooks();

$hooks();
}

/**
* nestedAroundHooks
*
* @return Closure
*/
protected function nestedAroundHooks()
{
$final_hook = [$this, 'performJob'];

$around_hooks = array_reverse($this->hooks[self::HOOKS_AROUND]);

$args = $this->args;

$job = $this->job;

return array_reduce(
$around_hooks,
function ($last_hook, $hook) use ($args, $job) {
$callback = [$job, $hook];
return function() use ($callback, $last_hook, $args) {
call_user_func_array($callback, [$args, $last_hook]);
};
},
$final_hook
);
}

/**
* performJob
*
* @return mixed
*/
public function performJob()
{
$result = $this->job->perform($this->args);
$this->performed = true;
return $result;
}
}
87 changes: 87 additions & 0 deletions lib/Resque/Plugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php

/**
* Plugin
*
* @package Resque
* @author Protec Innovations <[email protected]>
* @license http://www.opensource.org/licenses/mit-license.php
*/
class Resque_Plugin
{
const PREFIX_BEFORE_PERFORM = 'beforePerform';
const PREFIX_AFTER_PERFORM = 'afterPerform';
const PREFIX_AROUND_PERFORM = 'aroundPerform';

/**
* beforeHooks
*
* @param object $job
*
* @return array
*/
public static function beforeHooks($job)
{
return self::getMethodsWithPrefix($job, self::PREFIX_BEFORE_PERFORM);
}

/**
* afterHooks
*
* @param object $job
*
* @return array
*/
public static function afterHooks($job)
{
return self::getMethodsWithPrefix($job, self::PREFIX_AFTER_PERFORM);
}

/**
* aroundHooks
*
* @param object $job
*
* @return array
*/
public static function aroundHooks($job)
{
return self::getMethodsWithPrefix($job, self::PREFIX_AROUND_PERFORM);
}

/**
* getMethodsWithPrefix
*
* @param object $class
* @param string $prefix
*
* @return array
*/
protected static function getMethodsWithPrefix($class, $prefix)
{
$reflection = new ReflectionClass($class);

$has_basic_hook = false;

$return = [];

foreach ($reflection->getMethods() as $method) {
$method_name = $method->getName();

if (substr($method_name, 0, strlen($prefix)) == $prefix) {
if (strlen($prefix) == strlen($method_name)) {
$has_basic_hook = true;
} else {
$return[] = $method_name;
}
}
}

// Make sure we add the "basic" one last
if ($has_basic_hook) {
$return[] = $prefix;
}

return $return;
}
}
2 changes: 1 addition & 1 deletion test/Resque/Tests/EventTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function getEventTestJob()
'class' => 'Test_Job',
'id' => 'randomId',
'args' => array(
'somevar',
['somevar'],
),
);
$job = new Resque_Job('jobs', $payload);
Expand Down
2 changes: 1 addition & 1 deletion test/Resque/Tests/JobStatusTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,4 @@ public function testRecreatedJobWithTrackingStillTracksStatus()
$newJob = Resque_Job::reserve('jobs');
$this->assertEquals(Resque_Job_Status::STATUS_WAITING, $newJob->getStatus());
}
}
}
Loading