From ea441e7e8deb905a4bffce21a5d9881035f2355c Mon Sep 17 00:00:00 2001 From: "chris.boulton" Date: Sun, 27 Mar 2011 19:19:30 +1100 Subject: [PATCH 001/194] Update release date for 1.1 --- CHANGELOG.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index 38e57daa..a4b2af27 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -1,4 +1,4 @@ -## 1.1 (2011-02-26) ## +## 1.1 (2011-03-27) ## * Update Redisent library for Redis 2.2 compatibility. Redis 2.2 is now required. (thedotedge) * Trim output of `ps` to remove any prepended whitespace (KevBurnsJr) From 91c6fff601a4915c260c72888929e76a2976f70d Mon Sep 17 00:00:00 2001 From: Josh Hawthorne Date: Thu, 14 Apr 2011 19:43:04 -0500 Subject: [PATCH 002/194] updated readme example of how to setBackend to use a single param with a colon for server:port rather than two separate variables --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index ab490bdd..7066213f 100644 --- a/README.markdown +++ b/README.markdown @@ -47,7 +47,7 @@ Jobs are queued as follows: require_once 'lib/Resque.php'; // Required if redis is located elsewhere - Resque::setBackend('localhost', 6379); + Resque::setBackend('localhost:6379'); $args = array( 'name' => 'Chris' From cd3b0cca0eb4f9be6d5f4629b65679834ae59d3d Mon Sep 17 00:00:00 2001 From: humancopy Date: Wed, 18 May 2011 18:34:29 +0200 Subject: [PATCH 003/194] Set autoload to false for 'class_exists' calls. Currently it is not set, so the default is true which causes any defined '__autoload' function in the included app to be called. --- lib/Resque/Job.php | 2 +- lib/Resque/Redis.php | 2 +- lib/Resque/RedisCluster.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 9d674f5c..5df0fb67 100644 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -142,7 +142,7 @@ public function getInstance() return $this->instance; } - if(!class_exists($this->payload['class'])) { + if(!class_exists($this->payload['class'], false)) { throw new Resque_Exception( 'Could not find job class ' . $this->payload['class'] . '.' ); diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 874bf696..78d3ac7b 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -1,7 +1,7 @@ Date: Tue, 14 Jun 2011 19:29:43 +1000 Subject: [PATCH 004/194] Update changelog to mention bug fix by andrewjshults --- CHANGELOG.markdown | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index a4b2af27..97a95819 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -1,3 +1,7 @@ +## 1.2 (Unreleased) ## + +* Use `require_once` when including php-resque after the app has been included in the sample resque.php to prevent include conflicts (andrewjshults) + ## 1.1 (2011-03-27) ## * Update Redisent library for Redis 2.2 compatibility. Redis 2.2 is now required. (thedotedge) From 27beb8cc20a8a2ea1a69813c3bc08786d0f6e347 Mon Sep 17 00:00:00 2001 From: Patrick Bajao Date: Mon, 17 Jan 2011 00:44:17 +0800 Subject: [PATCH 005/194] Added database parameter in setBackend() to select the database for a connection. The default database is set to 0. --- lib/Resque.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Resque.php b/lib/Resque.php index 168d849a..c28a889a 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -37,6 +37,8 @@ public static function setBackend($server) require_once dirname(__FILE__) . '/Resque/Redis.php'; self::$redis = new Resque_Redis($host, $port); } + + self::redis()->select($database); } /** From 863099564e401eee7552e2327b2889c049b2a211 Mon Sep 17 00:00:00 2001 From: Patrick Bajao Date: Mon, 17 Jan 2011 01:15:31 +0800 Subject: [PATCH 006/194] Modified setBackend() to accept as the second parameter --- lib/Resque.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque.php b/lib/Resque.php index c28a889a..d429ae5d 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -26,7 +26,7 @@ class Resque * @param mixed $server Host/port combination separated by a colon, or * a nested array of servers with host/port pairs. */ - public static function setBackend($server) + public static function setBackend($server, $database = 0) { if(is_array($server)) { require_once dirname(__FILE__) . '/Resque/RedisCluster.php'; From 2a73e5b3901e1a94195007ad06ac819bdcf2d3e2 Mon Sep 17 00:00:00 2001 From: "chris.boulton" Date: Tue, 14 Jun 2011 19:36:29 +1000 Subject: [PATCH 007/194] Update changelog to include details of patrickbajao's modifications to allow setBackend to accept a redis database to use as a second argument --- CHANGELOG.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index 97a95819..ba4193dc 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -1,5 +1,6 @@ ## 1.2 (Unreleased) ## +* Allow alternate redis database to be selected when calling setBackend by supplying a second argument (patrickbajao) * Use `require_once` when including php-resque after the app has been included in the sample resque.php to prevent include conflicts (andrewjshults) ## 1.1 (2011-03-27) ## From f7eac3b5e7696c0f7c78750a2b9a5f63d4102e48 Mon Sep 17 00:00:00 2001 From: warezthebeef Date: Thu, 21 Jul 2011 15:49:18 +1200 Subject: [PATCH 008/194] Added wrapping array() to args to improve compatibility with ruby resque --- lib/Resque/Job.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 9d674f5c..c8204122 100644 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -63,7 +63,7 @@ public static function create($queue, $class, $args = null, $monitor = false) $id = md5(uniqid('', true)); Resque::push($queue, array( 'class' => $class, - 'args' => $args, + 'args' => array($args), 'id' => $id, )); @@ -128,7 +128,7 @@ public function getArguments() return array(); } - return $this->payload['args']; + return array_shift($this->payload['args']); } /** @@ -248,4 +248,4 @@ public function __toString() return '(' . implode(' | ', $name) . ')'; } } -?> \ No newline at end of file +?> From 0cfb2d20190a501ec84c7308678d627a2bc16558 Mon Sep 17 00:00:00 2001 From: warezthebeef Date: Fri, 19 Aug 2011 12:33:05 +1200 Subject: [PATCH 009/194] Fixed job arguments being wiped by array_shift --- lib/Resque/Job.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index c8204122..ee4aabae 100644 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -128,7 +128,7 @@ public function getArguments() return array(); } - return array_shift($this->payload['args']); + return $this->payload['args'][0]; } /** From 700af834b4e0d707badf78bc23a11112d772d110 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Fri, 16 Sep 2011 15:30:36 +1000 Subject: [PATCH 010/194] Unit tests should not be directly accessing payload[args] now that we have getArguments() --- test/Resque/Tests/JobTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Resque/Tests/JobTest.php b/test/Resque/Tests/JobTest.php index df6187b4..1f33fee9 100644 --- a/test/Resque/Tests/JobTest.php +++ b/test/Resque/Tests/JobTest.php @@ -65,7 +65,7 @@ public function testQueuedJobReturnsExactSamePassedInArguments() Resque::enqueue('jobs', 'Test_Job', $args); $job = Resque_Job::reserve('jobs'); - $this->assertEquals($args, $job->payload['args']); + $this->assertEquals($args, $job->getArguments()); } public function testAfterJobIsReservedItIsRemoved() @@ -97,7 +97,7 @@ public function testRecreatedJobMatchesExistingJob() $newJob = Resque_Job::reserve('jobs'); $this->assertEquals($job->payload['class'], $newJob->payload['class']); - $this->assertEquals($job->payload['args'], $newJob->payload['args']); + $this->assertEquals($job->payload['args'], $newJob->getArguments()); } public function testFailedJobExceptionsAreCaught() From c90e21d88eb2a495c52dfb81d95b3af701995029 Mon Sep 17 00:00:00 2001 From: d11wtq Date: Sat, 24 Sep 2011 15:08:53 +1000 Subject: [PATCH 011/194] Fix a bug where the worker would spin out of control taking the server with it, if the redis connection was interrupted even briefly. Use SIGPIPE to trap this scenario cleanly. --- lib/Redisent/Redisent.php | 4 ++++ lib/Resque/Worker.php | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/Redisent/Redisent.php b/lib/Redisent/Redisent.php index ac70c81e..19f5cdf1 100644 --- a/lib/Redisent/Redisent.php +++ b/lib/Redisent/Redisent.php @@ -49,6 +49,10 @@ class Redisent { function __construct($host, $port = 6379) { $this->host = $host; $this->port = $port; + $this->establishConnection(); + } + + function establishConnection() { $this->__sock = fsockopen($this->host, $this->port, $errno, $errstr); if (!$this->__sock) { throw new Exception("{$errno} - {$errstr}"); diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index a5c70b9b..3e7eefc4 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -358,6 +358,7 @@ private function registerSigHandlers() pcntl_signal(SIGUSR1, array($this, 'killChild')); pcntl_signal(SIGUSR2, array($this, 'pauseProcessing')); pcntl_signal(SIGCONT, array($this, 'unPauseProcessing')); + pcntl_signal(SIGPIPE, array($this, 'reestablishRedisConnection')); $this->log('Registered signals', self::LOG_VERBOSE); } @@ -380,6 +381,15 @@ public function unPauseProcessing() $this->paused = false; } + /** + * Signal handler for SIGPIPE, in the event the redis connection has gone away. + * Attempts to reconnect to redis, or raises an Exception. + */ + public function reestablishRedisConnection() { + $this->log('SIGPIPE received; attempting to reconnect'); + Resque::redis()->establishConnection(); + } + /** * Schedule a worker for shutdown. Will finish processing the current job * and when the timeout interval is reached, the worker will shut down. From 3514a4f063ce529954ab531e359cfb4317e8410d Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 24 Sep 2011 15:40:20 +1000 Subject: [PATCH 012/194] Move brace to new line --- lib/Resque/Worker.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 3e7eefc4..a180d27b 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -385,7 +385,8 @@ public function unPauseProcessing() * Signal handler for SIGPIPE, in the event the redis connection has gone away. * Attempts to reconnect to redis, or raises an Exception. */ - public function reestablishRedisConnection() { + public function reestablishRedisConnection() + { $this->log('SIGPIPE received; attempting to reconnect'); Resque::redis()->establishConnection(); } From 4c025119cc91fe160caf50959f0d28dd5daa1734 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 24 Sep 2011 15:42:28 +1000 Subject: [PATCH 013/194] Update changelog --- CHANGELOG.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index ba4193dc..84ae07c7 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -2,6 +2,8 @@ * Allow alternate redis database to be selected when calling setBackend by supplying a second argument (patrickbajao) * Use `require_once` when including php-resque after the app has been included in the sample resque.php to prevent include conflicts (andrewjshults) +* Wrap job arguments in an array to improve compatibility with ruby resque (warezthebeef) +* Fix a bug where the worker would spin out of control taking the server with it, if the redis connection was interrupted even briefly. Use SIGPIPE to trap this scenario cleanly. (d11wtq) ## 1.1 (2011-03-27) ## From c52bcc8af77acc39a4d95ff5e91256a3fb16bc61 Mon Sep 17 00:00:00 2001 From: humancopy Date: Wed, 2 Nov 2011 11:59:33 +0100 Subject: [PATCH 014/194] Re-enable autoload for class_exists in Job.php --- lib/Resque/Job.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 4667b407..ee4aabae 100644 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -142,7 +142,7 @@ public function getInstance() return $this->instance; } - if(!class_exists($this->payload['class'], false)) { + if(!class_exists($this->payload['class'])) { throw new Resque_Exception( 'Could not find job class ' . $this->payload['class'] . '.' ); From 016a7a13fdd658f41206507338611f39954745fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9lio=20Costa=20e=20Silva?= Date: Tue, 22 Nov 2011 14:55:40 -0200 Subject: [PATCH 015/194] Added support of Redis prefix (namespaces) --- lib/Resque/Redis.php | 23 ++++++++++++++++++++--- lib/Resque/RedisCluster.php | 21 +++++++++++++++++++-- test/Resque/Tests/JobTest.php | 15 +++++++++++++++ 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 874bf696..0d67a740 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -16,6 +16,11 @@ */ class Resque_Redis extends Redisent { + /** + * Redis namespace + * @var string + */ + private static $defaultNamespace = 'resque:'; /** * @var array List of all commands in Redis that supply a key as their * first argument. Used to prefix keys with the Resque namespace. @@ -76,10 +81,22 @@ class Resque_Redis extends Redisent // msetnx // mset // renamenx - + + /** + * Set Redis namespace (prefix) default: resque + * @param string $namespace + */ + public static function prefix($namespace) + { + if (strpos($namespace, ':') === false) { + $namespace .= ':'; + } + self::$defaultNamespace = $namespace; + } + /** * Magic method to handle all function requests and prefix key based - * operations with the 'resque:' key prefix. + * operations with the {self::$defaultNamespace} key prefix. * * @param string $name The name of the method called. * @param array $args Array of supplied arguments to the method. @@ -88,7 +105,7 @@ class Resque_Redis extends Redisent public function __call($name, $args) { $args = func_get_args(); if(in_array($name, $this->keyCommands)) { - $args[1][0] = 'resque:' . $args[1][0]; + $args[1][0] = self::$defaultNamespace . $args[1][0]; } try { return parent::__call($name, $args[1]); diff --git a/lib/Resque/RedisCluster.php b/lib/Resque/RedisCluster.php index 6ac15e3f..92972878 100644 --- a/lib/Resque/RedisCluster.php +++ b/lib/Resque/RedisCluster.php @@ -16,6 +16,11 @@ */ class Resque_RedisCluster extends RedisentCluster { + /** + * Redis namespace + * @var string + */ + private static $defaultNamespace = 'resque:'; /** * @var array List of all commands in Redis that supply a key as their * first argument. Used to prefix keys with the Resque namespace. @@ -76,10 +81,22 @@ class Resque_RedisCluster extends RedisentCluster // msetnx // mset // renamenx + + /** + * Set Redis namespace (prefix) default: resque + * @param string $namespace + */ + public static function prefix($namespace) + { + if (strpos($namespace, ':') === false) { + $namespace .= ':'; + } + self::$defaultNamespace = $namespace; + } /** * Magic method to handle all function requests and prefix key based - * operations with the 'resque:' key prefix. + * operations with the '{self::$defaultNamespace}' key prefix. * * @param string $name The name of the method called. * @param array $args Array of supplied arguments to the method. @@ -88,7 +105,7 @@ class Resque_RedisCluster extends RedisentCluster public function __call($name, $args) { $args = func_get_args(); if(in_array($name, $this->keyCommands)) { - $args[1][0] = 'resque:' . $args[1][0]; + $args[1][0] = self::$defaultNamespace . $args[1][0]; } try { return parent::__call($name, $args[1]); diff --git a/test/Resque/Tests/JobTest.php b/test/Resque/Tests/JobTest.php index 1f33fee9..31022912 100644 --- a/test/Resque/Tests/JobTest.php +++ b/test/Resque/Tests/JobTest.php @@ -100,6 +100,7 @@ public function testRecreatedJobMatchesExistingJob() $this->assertEquals($job->payload['args'], $newJob->getArguments()); } + public function testFailedJobExceptionsAreCaught() { $payload = array( @@ -166,4 +167,18 @@ public function testJobWithTearDownCallbackFiresTearDown() $this->assertTrue(Test_Job_With_TearDown::$called); } + + public function testJobWithNamespace() + { + Resque_Redis::prefix('php'); + $queue = 'jobs'; + $payload = array('another_value'); + Resque::enqueue($queue, 'Test_Job_With_TearDown', $payload); + + $this->assertEquals(Resque::queues(), array('jobs')); + $this->assertEquals(Resque::size($queue), 1); + + Resque_Redis::prefix('resque'); + $this->assertEquals(Resque::size($queue), 0); + } } \ No newline at end of file From 68df9854a6d17e7f621db31e8226bd0d3aa23f0e Mon Sep 17 00:00:00 2001 From: Salimane Adjao Moustapha Date: Wed, 7 Dec 2011 17:14:17 +0800 Subject: [PATCH 016/194] when reserving jobs, check if the payload received from popping a queue is a valid object (fix bug whereby jobs are reserved based on an erroneous payload) --- lib/Resque/Job.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index ee4aabae..257a3a39 100644 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -27,7 +27,7 @@ class Resque_Job * @var object Object containing details of the job. */ public $payload; - + /** * @var object Instance of the class performing work for this job. */ @@ -84,7 +84,7 @@ public static function create($queue, $class, $args = null, $monitor = false) public static function reserve($queue) { $payload = Resque::pop($queue); - if(!$payload) { + if(!is_object($payload)) { return false; } @@ -116,7 +116,7 @@ public function getStatus() $status = new Resque_Job_Status($this->payload['id']); return $status->get(); } - + /** * Get the arguments supplied to this job. * @@ -127,10 +127,10 @@ public function getArguments() if (!isset($this->payload['args'])) { return array(); } - + return $this->payload['args'][0]; } - + /** * Get the instantiated object for this job that will be performing work. * @@ -171,7 +171,7 @@ public function perform() $instance = $this->getInstance(); try { Resque_Event::trigger('beforePerform', $this); - + if(method_exists($instance, 'setUp')) { $instance->setUp(); } @@ -188,7 +188,7 @@ public function perform() catch(Resque_Job_DontPerform $e) { return false; } - + return true; } From 458fd6488b1db90623d737ef8b40801a039ce664 Mon Sep 17 00:00:00 2001 From: Salimane Adjao Moustapha Date: Thu, 8 Dec 2011 11:15:46 +0800 Subject: [PATCH 017/194] replace is_object with is_array when reserving jobs since Resque::pop actually returns an array instead of an object --- lib/Resque.php | 4 ++-- lib/Resque/Job.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index d429ae5d..c5fe038f 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -73,7 +73,7 @@ public static function push($queue, $item) * return it. * * @param string $queue The name of the queue to fetch an item from. - * @return object Decoded item from the queue. + * @return array Decoded item from the queue. */ public static function pop($queue) { @@ -113,7 +113,7 @@ public static function enqueue($queue, $class, $args = null, $trackStatus = fals 'args' => $args, )); } - + return $result; } diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 257a3a39..654271a1 100644 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -37,7 +37,7 @@ class Resque_Job * Instantiate a new instance of a job. * * @param string $queue The queue that the job belongs to. - * @param object $payload Object containing details of the job. + * @param array $payload array containing details of the job. */ public function __construct($queue, $payload) { @@ -84,7 +84,7 @@ public static function create($queue, $class, $args = null, $monitor = false) public static function reserve($queue) { $payload = Resque::pop($queue); - if(!is_object($payload)) { + if(!is_array($payload)) { return false; } From 7a7cfbf2b9122e8958d2d3a881764eecee44c751 Mon Sep 17 00:00:00 2001 From: Salimane Adjao Moustapha Date: Fri, 16 Dec 2011 10:30:42 +0800 Subject: [PATCH 018/194] fix comment to specify that is an array instead of an object in Resque::push --- lib/Resque.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque.php b/lib/Resque.php index c5fe038f..d0be4655 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -60,7 +60,7 @@ public static function redis() * exist, then create it as well. * * @param string $queue The name of the queue to add the job to. - * @param object $item Job description as an object to be JSON encoded. + * @param array $item Job description as an array to be JSON encoded. */ public static function push($queue, $item) { From 0ac835a630e5081af6bcfe1e6a9a26814b1cb9d1 Mon Sep 17 00:00:00 2001 From: pedroarnal Date: Wed, 25 Jan 2012 00:46:34 +0100 Subject: [PATCH 019/194] Enabling use of unix sockets on Redis backend. --- lib/Resque.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/Resque.php b/lib/Resque.php index d0be4655..f4dbbd95 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -33,7 +33,13 @@ public static function setBackend($server, $database = 0) self::$redis = new Resque_RedisCluster($server); } else { - list($host, $port) = explode(':', $server); + if (strpos($server, 'unix:') === false) { + list($host, $port) = explode(':', $server); + } + else { + $host = $server; + $port = null; + } require_once dirname(__FILE__) . '/Resque/Redis.php'; self::$redis = new Resque_Redis($host, $port); } From 5b24b471dc393daf0317f9bec98def56f53e52b5 Mon Sep 17 00:00:00 2001 From: Salimane Adjao Moustapha Date: Thu, 2 Feb 2012 15:49:59 +0800 Subject: [PATCH 020/194] avoid working with dirty worker ids --- lib/Resque/Worker.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index a180d27b..6bef8f32 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -53,7 +53,7 @@ class Resque_Worker * @var Resque_Job Current job, if any, being processed by this worker. */ private $currentJob = null; - + /** * @var int Process ID of child worker processes. */ @@ -95,7 +95,7 @@ public static function exists($workerId) */ public static function find($workerId) { - if(!self::exists($workerId)) { + if(!self::exists($workerId) || false === strpos($workerId, ":")) { return false; } @@ -447,12 +447,14 @@ public function pruneDeadWorkers() $workerPids = $this->workerPids(); $workers = self::all(); foreach($workers as $worker) { - list($host, $pid, $queues) = explode(':', (string)$worker, 3); - if($host != $this->hostname || in_array($pid, $workerPids) || $pid == getmypid()) { - continue; - } - $this->log('Pruning dead worker: ' . (string)$worker, self::LOG_VERBOSE); - $worker->unregisterWorker(); + if (is_object($worker)) { + list($host, $pid, $queues) = explode(':', (string)$worker, 3); + if($host != $this->hostname || in_array($pid, $workerPids) || $pid == getmypid()) { + continue; + } + $this->log('Pruning dead worker: ' . (string)$worker, self::LOG_VERBOSE); + $worker->unregisterWorker(); + } } } From 782d0317e630a18a343ae958626d79cad2bbe2b4 Mon Sep 17 00:00:00 2001 From: pedroarnal Date: Sat, 18 Feb 2012 17:10:06 +0100 Subject: [PATCH 021/194] Update lib/Resque/Redis.php --- lib/Resque/Redis.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 0a6908f8..b6d7522d 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -39,7 +39,7 @@ class Resque_Redis extends Redisent 'setnx', 'incr', 'incrby', - 'decrby', + 'decr', 'decrby', 'rpush', 'lpush', From 951d9d37b56da665e39a1ea9ea5af21540339bf7 Mon Sep 17 00:00:00 2001 From: Chaitanya Kuber Date: Wed, 29 Feb 2012 22:32:52 -0600 Subject: [PATCH 022/194] updated method comments --- lib/Resque.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index d0be4655..0efa24dc 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -24,7 +24,8 @@ class Resque * the redis server that Resque will talk to. * * @param mixed $server Host/port combination separated by a colon, or - * a nested array of servers with host/port pairs. + * a nested array of servers with host/port pairs. + * @param int $database */ public static function setBackend($server, $database = 0) { @@ -88,6 +89,8 @@ public static function pop($queue) /** * Return the size (number of pending jobs) of the specified queue. * + * @param $queue name of the queue to be checked for pendign jobs + * * @return int The size of the queue. */ public static function size($queue) @@ -101,7 +104,9 @@ public static function size($queue) * @param string $queue The name of the queue to place the job in. * @param string $class The name of the class that contains the code to execute the job. * @param array $args Any optional arguments that should be passed when the job is executed. - * @param boolean $monitor Set to true to be able to monitor the status of a job. + * @param boolean $trackStatus Set to true to be able to monitor the status of a job. + * + * @return string */ public static function enqueue($queue, $class, $args = null, $trackStatus = false) { From 2c5e0881981086b4122e219e9419de85c54f9f9f Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Thu, 1 Mar 2012 16:33:26 +1100 Subject: [PATCH 023/194] move include for resque before APP_INCLUDE is loaded in, so that way resque is available for the app --- resque.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/resque.php b/resque.php index d85a70ea..02ecc1ab 100644 --- a/resque.php +++ b/resque.php @@ -4,15 +4,6 @@ die("Set QUEUE env var containing the list of queues to work.\n"); } -$APP_INCLUDE = getenv('APP_INCLUDE'); -if($APP_INCLUDE) { - if(!file_exists($APP_INCLUDE)) { - die('APP_INCLUDE ('.$APP_INCLUDE.") does not exist.\n"); - } - - require_once $APP_INCLUDE; -} - require_once 'lib/Resque.php'; require_once 'lib/Resque/Worker.php'; @@ -32,6 +23,15 @@ $logLevel = Resque_Worker::LOG_VERBOSE; } +$APP_INCLUDE = getenv('APP_INCLUDE'); +if($APP_INCLUDE) { + if(!file_exists($APP_INCLUDE)) { + die('APP_INCLUDE ('.$APP_INCLUDE.") does not exist.\n"); + } + + require_once $APP_INCLUDE; +} + $interval = 5; $INTERVAL = getenv('INTERVAL'); if(!empty($INTERVAL)) { From 8f06294048f7cc8ea7954230ea9426085ca6c0b4 Mon Sep 17 00:00:00 2001 From: Chaitanya Kuber Date: Thu, 1 Mar 2012 19:13:34 -0600 Subject: [PATCH 024/194] method comments updated --- lib/Resque/Failure.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Resque/Failure.php b/lib/Resque/Failure.php index 844e3434..9f6d89a7 100644 --- a/lib/Resque/Failure.php +++ b/lib/Resque/Failure.php @@ -19,10 +19,10 @@ class Resque_Failure /** * Create a new failed job on the backend. * - * @param object $payload The contents of the job that has just failed. - * @param object $exception The exception generated when the job failed to run. - * @param object $worker Instance of Resque_Worker that was running this job when it failed. - * @param string $queue The name of the queue that this job was fetched from. + * @param object $payload The contents of the job that has just failed. + * @param \Exception $exception The exception generated when the job failed to run. + * @param \Resque_Worker $worker Instance of Resque_Worker that was running this job when it failed. + * @param string $queue The name of the queue that this job was fetched from. */ public static function create($payload, Exception $exception, Resque_Worker $worker, $queue) { From ef859b6fc5861873daedfaf4959b08b125cf9dd0 Mon Sep 17 00:00:00 2001 From: Chaitanya Kuber Date: Thu, 1 Mar 2012 19:21:06 -0600 Subject: [PATCH 025/194] updated method comments --- lib/Resque/Job.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 654271a1..e2002ad2 100644 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -52,6 +52,8 @@ public function __construct($queue, $payload) * @param string $class The name of the class that contains the code to execute the job. * @param array $args Any optional arguments that should be passed when the job is executed. * @param boolean $monitor Set to true to be able to monitor the status of a job. + * + * @return string */ public static function create($queue, $class, $args = null, $monitor = false) { @@ -154,7 +156,7 @@ public function getInstance() ); } - $this->instance = new $this->payload['class']; + $this->instance = new $this->payload['class'](); $this->instance->job = $this; $this->instance->args = $this->getArguments(); return $this->instance; @@ -164,6 +166,7 @@ public function getInstance() * Actually execute a job by calling the perform method on the class * associated with the job with the supplied arguments. * + * @return bool * @throws Resque_Exception When the job's class could not be found or it does not contain a perform method. */ public function perform() @@ -194,6 +197,8 @@ public function perform() /** * Mark the current job as having failed. + * + * @param $exception */ public function fail($exception) { @@ -216,6 +221,7 @@ public function fail($exception) /** * Re-queue the current job. + * @return string */ public function recreate() { From 3b59fa5dbcf23b4643d1e9e8395e1e58038fbec6 Mon Sep 17 00:00:00 2001 From: Chaitanya Kuber Date: Thu, 1 Mar 2012 19:21:58 -0600 Subject: [PATCH 026/194] method comment changes --- lib/Resque/Worker.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index a180d27b..189cf814 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -53,7 +53,7 @@ class Resque_Worker * @var Resque_Job Current job, if any, being processed by this worker. */ private $currentJob = null; - + /** * @var int Process ID of child worker processes. */ @@ -61,6 +61,7 @@ class Resque_Worker /** * Return all workers known to Resque as instantiated instances. + * @return array */ public static function all() { @@ -192,12 +193,12 @@ public function work($interval = 5) $this->child = $this->fork(); // Forked and we're the child. Run the job. - if($this->child === 0 || $this->child === false) { + if ($this->child === 0 || $this->child === false) { $status = 'Processing ' . $job->queue . ' since ' . strftime('%F %T'); $this->updateProcLine($status); $this->log($status, self::LOG_VERBOSE); $this->perform($job); - if($this->child === 0) { + if ($this->child === 0) { exit(0); } } @@ -228,11 +229,12 @@ public function work($interval = 5) /** * Process a single job. * - * @param object|null $job The job to be processed. + * @param Resque_Job $job The job to be processed. */ public function perform(Resque_Job $job) { try { + $this->log("afterFork being triggered", self::LOG_VERBOSE); Resque_Event::trigger('afterFork', $job); $job->perform(); } From ebe76658175a7a8c9f190db6747a91f0c91eb988 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Mon, 5 Mar 2012 19:21:43 +1100 Subject: [PATCH 027/194] fix lost jobs when there is more than one worker process started by the same parent process --- lib/Resque.php | 59 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index d0be4655..a997356a 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -19,6 +19,23 @@ class Resque */ public static $redis = null; + /** + * @var mixed Host/port conbination separated by a colon, or a nested + * array of server swith host/port pairs + */ + protected static $redisServer = null; + + /** + * @var int ID of Redis database to select. + */ + protected static $redisDatabase = 0; + + /** + * @var int PID of current process. Used to detect changes when forking + * and implement "thread" safety to avoid race conditions. + */ + protected static $pid = null; + /** * Given a host/port combination separated by a colon, set it as * the redis server that Resque will talk to. @@ -28,17 +45,9 @@ class Resque */ public static function setBackend($server, $database = 0) { - if(is_array($server)) { - require_once dirname(__FILE__) . '/Resque/RedisCluster.php'; - self::$redis = new Resque_RedisCluster($server); - } - else { - list($host, $port) = explode(':', $server); - require_once dirname(__FILE__) . '/Resque/Redis.php'; - self::$redis = new Resque_Redis($host, $port); - } - - self::redis()->select($database); + self::$redisServer = $server; + self::$redisDatabase = $database; + self::$redis = null; } /** @@ -48,10 +57,34 @@ public static function setBackend($server, $database = 0) */ public static function redis() { - if(is_null(self::$redis)) { - self::setBackend('localhost:6379'); + // Detect when the PID of the current process has changed (from a fork, etc) + // and force a reconnect to redis. + $pid = getmypid(); + if (self::$pid !== $pid) { + self::$redis = null; + self::$pid = $pid; + } + + if(!is_null(self::$redis)) { + return self::$redis; + } + + $server = self::$redisServer; + if (empty($server)) { + $server = 'localhost:6379'; + } + + if(is_array($server)) { + require_once dirname(__FILE__) . '/Resque/RedisCluster.php'; + self::$redis = new Resque_RedisCluster($server); + } + else { + list($host, $port) = explode(':', $server); + require_once dirname(__FILE__) . '/Resque/Redis.php'; + self::$redis = new Resque_Redis($host, $port); } + self::$redis->select(self::$redisDatabase); return self::$redis; } From 8259dc7491346ccaee73ab5c0d80f31fa84435a7 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Mon, 5 Mar 2012 19:35:56 +1100 Subject: [PATCH 028/194] update changelog --- CHANGELOG.markdown | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index 84ae07c7..8f2d66ba 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -4,6 +4,13 @@ * Use `require_once` when including php-resque after the app has been included in the sample resque.php to prevent include conflicts (andrewjshults) * Wrap job arguments in an array to improve compatibility with ruby resque (warezthebeef) * Fix a bug where the worker would spin out of control taking the server with it, if the redis connection was interrupted even briefly. Use SIGPIPE to trap this scenario cleanly. (d11wtq) +* Added support of Redis prefix (namespaces) (hlegius) +* When reserving jobs, check if the payload received from popping a queue is a valid object (fix bug whereby jobs are reserved based on an erroneous payload) (salimane) +* Re-enable autoload for class_exists in Job.php (humancopy) +* Fix lost jobs when there is more than one worker process started by the same parent process (salimane) +* Move include for resque before APP_INCLUDE is loaded in, so that way resque is available for the app +* Avoid working with dirty worker IDs (salimane) + ## 1.1 (2011-03-27) ## From e6464f4c792d362d9fbc4c0b4dc9131971f28d0a Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Mon, 5 Mar 2012 20:21:12 +1100 Subject: [PATCH 029/194] Require Redisent/Redis separately --- test/Resque/Tests/bootstrap.php | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Resque/Tests/bootstrap.php b/test/Resque/Tests/bootstrap.php index eb84258a..ad709c63 100644 --- a/test/Resque/Tests/bootstrap.php +++ b/test/Resque/Tests/bootstrap.php @@ -21,6 +21,7 @@ // Include Resque require_once RESQUE_LIB . 'Resque.php'; require_once RESQUE_LIB . 'Resque/Worker.php'; +require_once RESQUE_LIB . 'Resque/Redis.php'; // Attempt to start our own redis instance for tesitng. exec('which redis-server', $output, $returnVar); From cc871c06ab662dc38b33feca595f15edac03eab4 Mon Sep 17 00:00:00 2001 From: Chaitanya Kuber Date: Thu, 15 Mar 2012 20:03:34 -0500 Subject: [PATCH 030/194] fixed spelling error and removed debug code --- lib/Resque.php | 2 +- lib/Resque/Worker.php | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index ded12a42..df211a6c 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -128,7 +128,7 @@ public static function pop($queue) /** * Return the size (number of pending jobs) of the specified queue. * - * @param $queue name of the queue to be checked for pendign jobs + * @param $queue name of the queue to be checked for pending jobs * * @return int The size of the queue. */ diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index fc2e9d92..31f2f3ca 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -234,7 +234,6 @@ public function work($interval = 5) public function perform(Resque_Job $job) { try { - $this->log("afterFork being triggered", self::LOG_VERBOSE); Resque_Event::trigger('afterFork', $job); $job->perform(); } @@ -584,4 +583,4 @@ public function getStat($stat) return Resque_Stat::get($stat . ':' . $this); } } -?> \ No newline at end of file +?> From 016f046a6a557cae0ceff9d66c00bab8b02941a5 Mon Sep 17 00:00:00 2001 From: Chaitanya Kuber Date: Mon, 19 Mar 2012 07:14:02 +0800 Subject: [PATCH 031/194] Merge branch 'master', remote branch 'upstream/master' From 76c06a1349b2dc2a129936b2af3f863aa63aed7d Mon Sep 17 00:00:00 2001 From: Chaitanya Kuber Date: Thu, 22 Mar 2012 12:20:16 +0800 Subject: [PATCH 032/194] now setting the queue name onto the job instance --- lib/Resque/Job.php | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 lib/Resque/Job.php diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php old mode 100644 new mode 100755 index e2002ad2..0d275a12 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -159,6 +159,7 @@ public function getInstance() $this->instance = new $this->payload['class'](); $this->instance->job = $this; $this->instance->args = $this->getArguments(); + $this->instance->queue = $this->queue; return $this->instance; } From fab92ef114d43e1e54711b1b0ef16e7d20e2605b Mon Sep 17 00:00:00 2001 From: ebernhardson Date: Tue, 3 Apr 2012 15:23:25 -0700 Subject: [PATCH 033/194] fix bug preventing stopListening from working --- lib/Resque/Event.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Resque/Event.php b/lib/Resque/Event.php index 2264ae27..930c0671 100644 --- a/lib/Resque/Event.php +++ b/lib/Resque/Event.php @@ -73,7 +73,7 @@ public static function stopListening($event, $callback) $key = array_search($callback, self::$events[$event]); if ($key !== false) { - unset(self::$events[$key]); + unset(self::$events[$event][$key]); } return true; @@ -86,4 +86,4 @@ public static function clearListeners() { self::$events = array(); } -} \ No newline at end of file +} From 010384b2965970366ea9ca1c9b87046d4bf25e40 Mon Sep 17 00:00:00 2001 From: ebernhardson Date: Wed, 4 Apr 2012 18:27:08 -0700 Subject: [PATCH 034/194] unit test to verify fix of Resque_Event::stopListening --- test/Resque/Tests/EventTest.php | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/test/Resque/Tests/EventTest.php b/test/Resque/Tests/EventTest.php index 3d2a5364..0bf5ee95 100644 --- a/test/Resque/Tests/EventTest.php +++ b/test/Resque/Tests/EventTest.php @@ -101,6 +101,24 @@ public function testAfterEnqueueEventCallbackFires() )); $this->assertContains($callback, $this->callbacksHit, $event . ' callback (' . $callback .') was not called'); } + + public function testStopListeningRemovesListener() + { + $callback = 'beforePerformEventCallback'; + $event = 'beforePerform'; + + Resque_Event::listen($event, array($this, $callback)); + Resque_Event::stopListening($event, array($this, $callback)); + + $job = $this->getEventTestJob(); + $this->worker->perform($job); + $this->worker->work(0); + + $this->assertNotContains($callback, $this->callbacksHit, + $event . ' callback (' . $callback .') was called though Resque_Event::stopListening was called' + ); + } + public function beforePerformEventDontPerformCallback($instance) { @@ -146,4 +164,4 @@ public function afterForkEventCallback($job) { $this->assertValidEventCallback(__FUNCTION__, $job); } -} \ No newline at end of file +} From ad7f4d1ab7b344248b18aef3ac2e41440f1357ff Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Thu, 19 Apr 2012 22:30:44 +1000 Subject: [PATCH 035/194] add .travis.yml to run unit tests on travis-ci --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..1284d21c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: php +php: + - 5.2 + - 5.3 + - 5.4 From 998b46887a806472796b5a0534cca939657ce81e Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Thu, 19 Apr 2012 22:36:15 +1000 Subject: [PATCH 036/194] add travis-ci status to readme --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 7066213f..fe88316a 100644 --- a/README.markdown +++ b/README.markdown @@ -1,4 +1,4 @@ -php-resque: PHP Resque Worker (and Enqueue) +php-resque: PHP Resque Worker (and Enqueue) [![Build Status](https://secure.travis-ci.org/chrisboulton/php-resque.png)](http://travis-ci.org/chrisboulton/php-resque) =========================================== Resque is a Redis-backed library for creating background jobs, placing From e54c7ca99a7a6bdd8105a459e0029c6840cd3b7f Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Thu, 19 Apr 2012 22:39:55 +1000 Subject: [PATCH 037/194] only remove pid file during tests if exists --- test/Resque/Tests/bootstrap.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test/Resque/Tests/bootstrap.php b/test/Resque/Tests/bootstrap.php index ad709c63..0efa2a84 100644 --- a/test/Resque/Tests/bootstrap.php +++ b/test/Resque/Tests/bootstrap.php @@ -59,11 +59,13 @@ function killRedis($pid) } $pidFile = TEST_MISC . '/' . $matches[1]; - $pid = trim(file_get_contents($pidFile)); - posix_kill((int) $pid, 9); - - if(is_file($pidFile)) { - unlink($pidFile); + if (file_exists($pidFile)) { + $pid = trim(file_get_contents($pidFile)); + posix_kill((int) $pid, 9); + + if(is_file($pidFile)) { + unlink($pidFile); + } } // Remove the redis database From c79ae86a56114c5492cb9a4022c168d334d045b7 Mon Sep 17 00:00:00 2001 From: maetl Date: Wed, 2 May 2012 19:36:02 +1000 Subject: [PATCH 038/194] use short filenames for markdown docs --- CHANGELOG.markdown => CHANGELOG.md | 0 README.markdown => README.md | 0 TODO.markdown => TODO.md | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename CHANGELOG.markdown => CHANGELOG.md (100%) rename README.markdown => README.md (100%) rename TODO.markdown => TODO.md (100%) diff --git a/CHANGELOG.markdown b/CHANGELOG.md similarity index 100% rename from CHANGELOG.markdown rename to CHANGELOG.md diff --git a/README.markdown b/README.md similarity index 100% rename from README.markdown rename to README.md diff --git a/TODO.markdown b/TODO.md similarity index 100% rename from TODO.markdown rename to TODO.md From df8853ee4fd07f797b0ba6fed47a5e2f0efe6685 Mon Sep 17 00:00:00 2001 From: maetl Date: Wed, 2 May 2012 19:37:36 +1000 Subject: [PATCH 039/194] removing a lie; adding some structure --- README.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index fe88316a..552b8a7a 100644 --- a/README.md +++ b/README.md @@ -4,31 +4,30 @@ php-resque: PHP Resque Worker (and Enqueue) [![Build Status](https://secure.trav Resque is a Redis-backed library for creating background jobs, placing those jobs on multiple queues, and processing them later. -Resque was pioneered and is developed by the fine folks at GitHub (yes, -I am a kiss-ass), and written in Ruby. +## Background ## -What you're seeing here is an almost direct port of the Resque worker -and enqueue system to PHP, which I've thrown together because I'm sure -my PHP developers would have a fit if they had to write a line of Ruby. +Resque was pioneered and is developed by the fine folks at GitHub (yes, +I am a kiss-ass), and written in Ruby. What you're seeing here is an +almost direct port of the Resque worker and enqueue system to PHP. For more information on Resque, visit the official GitHub project: -And for background information, the launch post on the GitHub blog: +For further information, see the launch post on the GitHub blog: The PHP port does NOT include its own web interface for viewing queue stats, as the data is stored in the exact same expected format as the Ruby version of Resque. -The PHP port allows for much the same as the Ruby version of Rescue: +The PHP port provides much the same features as the Ruby version: * Workers can be distributed between multiple machines * Includes support for priorities (queues) * Resilient to memory leaks (fork) * Expects failure -In addition, it also: +It also supports the following additional features: * Has the ability to track the status of jobs * Will mark a job as failed, if a forked child running a job does @@ -36,7 +35,10 @@ not exit with a status code as 0 * Has built in support for `setUp` and `tearDown` methods, called pre and post jobs -Note: php-resque requires at least Redis 2.2. +## Requirements ## + +* PHP 5.2+ +* Redis 2.2+ ## Jobs ## From b0fbfa4f15bae27eba38f6201e417c7ea55b3984 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Thu, 10 May 2012 22:13:28 +1000 Subject: [PATCH 040/194] make the queue for an enqueued job available in the afterEnqueue event --- README.md | 3 ++- lib/Resque.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 552b8a7a..2f942ab9 100644 --- a/README.md +++ b/README.md @@ -316,8 +316,9 @@ Called whenever a job fails. Arguments passed (in this order) include: Called after a job has been queued using the `Resque::enqueue` method. Arguments passed (in this order) include: -* Class - string containing the name of the class the job was scheduled in +* Class - string containing the name of scheduled job * Arguments - array of arguments supplied to the job +* Queue - string containing the name of the queue the job was added to ## Contributors ## diff --git a/lib/Resque.php b/lib/Resque.php index df211a6c..9bc81431 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -154,7 +154,8 @@ public static function enqueue($queue, $class, $args = null, $trackStatus = fals if ($result) { Resque_Event::trigger('afterEnqueue', array( 'class' => $class, - 'args' => $args, + 'args' => $args, + 'queue' => $queue, )); } From 5b89607e4bd256f0b13731ad58f958160f8b39aa Mon Sep 17 00:00:00 2001 From: Matt Heath Date: Thu, 10 May 2012 15:01:00 +0100 Subject: [PATCH 041/194] Fix issue #19 by ensuring RedisException is not redeclared --- lib/Redisent/Redisent.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Redisent/Redisent.php b/lib/Redisent/Redisent.php index 19f5cdf1..1580b895 100644 --- a/lib/Redisent/Redisent.php +++ b/lib/Redisent/Redisent.php @@ -11,8 +11,11 @@ /** * Wraps native Redis errors in friendlier PHP exceptions + * Only declared if class doesn't already exist to ensure compatibility with php-redis */ -class RedisException extends Exception { +if (! class_exists('RedisException')) { + class RedisException extends Exception { + } } /** From 905c39670353c691d76f4b46dca16174732609ce Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Wed, 1 Aug 2012 11:39:12 +1000 Subject: [PATCH 042/194] add basic composer.json. closes #59 --- composer.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 composer.json diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..594f13ff --- /dev/null +++ b/composer.json @@ -0,0 +1,22 @@ +{ + "name": "chrisboulton/php-resque", + "type": "library", + "description": "Redis backed library for creating background jobs and processing them later. Based on resque for Ruby.", + "keywords": ["job", "background", "redis", "resque"], + "homepage": "http://www.github.com/chrisboulton/php-resque/", + "license": "MIT", + "authors": [ + { + "name": "Chris Boulton", + "email": "chris@bigcommerce.com" + } + ], + "require": { + "php": ">=5.3.0" + }, + "autoload": { + "psr-0": { + "Resque": "lib" + } + } +} \ No newline at end of file From 26ae7a63da71268800ff106859df63b418a34a47 Mon Sep 17 00:00:00 2001 From: Joe Frey Date: Wed, 8 Aug 2012 16:19:53 -0400 Subject: [PATCH 043/194] fixing missing and incorrect paths for Resque class and Resque_Job_Status --- demo/check_status.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/demo/check_status.php b/demo/check_status.php index c5c194c9..c1959114 100644 --- a/demo/check_status.php +++ b/demo/check_status.php @@ -3,7 +3,8 @@ die('Specify the ID of a job to monitor the status of.'); } -require '../lib/resque.php'; +require '../lib/Resque/Job/Status.php'; +require '../lib/Resque.php'; date_default_timezone_set('GMT'); Resque::setBackend('127.0.0.1:6379'); @@ -17,4 +18,4 @@ fwrite(STDOUT, "Status of ".$argv[1]." is: ".$status->get()."\n"); sleep(1); } -?> \ No newline at end of file +?> From 41bf8c1c26708232252d85310402163c563e7e7e Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Fri, 24 Aug 2012 16:51:03 +0200 Subject: [PATCH 044/194] Basic support for blocking list pop --- lib/Resque.php | 17 ++++++++++----- lib/Resque/Job.php | 6 +++--- lib/Resque/Redis.php | 1 + lib/Resque/RedisCluster.php | 1 + lib/Resque/Worker.php | 42 ++++++++++++++++++------------------- 5 files changed, 38 insertions(+), 29 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index 9bc81431..4fe5a167 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -14,6 +14,8 @@ class Resque { const VERSION = '1.0'; + const DEFAULT_INTERVAL = 5; + /** * @var Resque_Redis Instance of Resque_Redis that talks to redis. */ @@ -115,14 +117,19 @@ public static function push($queue, $item) * @param string $queue The name of the queue to fetch an item from. * @return array Decoded item from the queue. */ - public static function pop($queue) + public static function pop($queue, $interval = null) { - $item = self::redis()->lpop('queue:' . $queue); + if($interval == null) { + $item = self::redis()->lpop('queue:' . $queue); + } else { + $item = self::redis()->blpop('queue:' . $queue, $interval ?: Resque::DEFAULT_INTERVAL); + } + if(!$item) { return; } - return json_decode($item, true); + return json_decode($interval == 0 ? $item : $item[1], true); } /** @@ -168,10 +175,10 @@ public static function enqueue($queue, $class, $args = null, $trackStatus = fals * @param string $queue Queue to fetch next available job from. * @return Resque_Job Instance of Resque_Job to be processed, false if none or error. */ - public static function reserve($queue) + public static function reserve($queue, $interval = null) { require_once dirname(__FILE__) . '/Resque/Job.php'; - return Resque_Job::reserve($queue); + return Resque_Job::reserve($queue, $interval); } /** diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 0d275a12..6af0219e 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -83,9 +83,9 @@ public static function create($queue, $class, $args = null, $monitor = false) * @param string $queue The name of the queue to check for a job in. * @return null|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. */ - public static function reserve($queue) + public static function reserve($queue, $interval = null) { - $payload = Resque::pop($queue); + $payload = Resque::pop($queue, $interval); if(!is_array($payload)) { return false; } @@ -156,7 +156,7 @@ public function getInstance() ); } - $this->instance = new $this->payload['class'](); + $this->instance = new $this->payload['class']; $this->instance->job = $this; $this->instance->args = $this->getArguments(); $this->instance->queue = $this->queue; diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index b6d7522d..e1f077f1 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -50,6 +50,7 @@ class Resque_Redis extends Redisent 'lset', 'lrem', 'lpop', + 'blpop', 'rpop', 'sadd', 'srem', diff --git a/lib/Resque/RedisCluster.php b/lib/Resque/RedisCluster.php index 39c3f5c6..e884653c 100644 --- a/lib/Resque/RedisCluster.php +++ b/lib/Resque/RedisCluster.php @@ -50,6 +50,7 @@ class Resque_RedisCluster extends RedisentCluster 'lset', 'lrem', 'lpop', + 'blpop', 'rpop', 'sadd', 'srem', diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 31f2f3ca..58571be9 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -153,7 +153,7 @@ public function __construct($queues) * * @param int $interval How often to check for new jobs across the queues. */ - public function work($interval = 5) + public function work($interval = Resque::DEFAULT_INTERVAL) { $this->updateProcLine('Starting'); $this->startup(); @@ -166,25 +166,25 @@ public function work($interval = 5) // Attempt to find and reserve a job $job = false; if(!$this->paused) { - $job = $this->reserve(); + $job = $this->reserve($interval); } - if(!$job) { - // For an interval of 0, break now - helps with unit testing etc - if($interval == 0) { - break; - } - // If no job was found, we sleep for $interval before continuing and checking again - $this->log('Sleeping for ' . $interval, true); - if($this->paused) { - $this->updateProcLine('Paused'); - } - else { - $this->updateProcLine('Waiting for ' . implode(',', $this->queues)); - } - usleep($interval * 1000000); - continue; - } + $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); + + if(!$job) { + // For an interval of 0, break now - helps with unit testing etc + if($interval == 0) { + break; + } + + // If no job was found, we sleep for $interval before continuing and checking again + if($this->paused) { + $this->updateProcLine('Paused'); + usleep($interval * 1000000); //it's paused, so don't hog redis with requests. + } + + continue; + } $this->log('got ' . $job); Resque_Event::trigger('beforeFork', $job); @@ -252,15 +252,15 @@ public function perform(Resque_Job $job) * * @return object|boolean Instance of Resque_Job if a job is found, false if not. */ - public function reserve() + public function reserve($interval = null) { $queues = $this->queues(); if(!is_array($queues)) { return; } foreach($queues as $queue) { - $this->log('Checking ' . $queue, self::LOG_VERBOSE); - $job = Resque_Job::reserve($queue); + $this->log('Checking ' . $queue . ' with interval ' . $interval, self::LOG_VERBOSE); + $job = Resque_Job::reserve($queue, $interval); if($job) { $this->log('Found job on ' . $queue, self::LOG_VERBOSE); return $job; From a8a7db51ca08e38667ed11ed4773aaedcddd3496 Mon Sep 17 00:00:00 2001 From: scragg0x Date: Fri, 7 Sep 2012 13:36:15 -0500 Subject: [PATCH 045/194] Disable autoload for the class_exists func MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I ran into an autoload problem because of this class_exists function. So I set the second arg to false to prevent it from calling __autoload.   It doesn't make sense to try (to autoload) anyway because it's going to declare a skeleton if the class doesn't exist. --- lib/Redisent/Redisent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Redisent/Redisent.php b/lib/Redisent/Redisent.php index 1580b895..4b480f66 100644 --- a/lib/Redisent/Redisent.php +++ b/lib/Redisent/Redisent.php @@ -13,7 +13,7 @@ * Wraps native Redis errors in friendlier PHP exceptions * Only declared if class doesn't already exist to ensure compatibility with php-redis */ -if (! class_exists('RedisException')) { +if (! class_exists('RedisException', false)) { class RedisException extends Exception { } } From 5eff86d3c3c54eedcfeecc515e02805d70d66ac2 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Mon, 10 Sep 2012 10:23:18 +0200 Subject: [PATCH 046/194] Fixed bug --- lib/Resque.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque.php b/lib/Resque.php index 4fe5a167..29249f0e 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -122,7 +122,7 @@ public static function pop($queue, $interval = null) if($interval == null) { $item = self::redis()->lpop('queue:' . $queue); } else { - $item = self::redis()->blpop('queue:' . $queue, $interval ?: Resque::DEFAULT_INTERVAL); + $item = self::redis()->blpop('queue:' . $queue, $interval ? $interval : Resque::DEFAULT_INTERVAL); } if(!$item) { From c6bd34d00d1b5e479f2340f9bcc0a5f2e85edf74 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 13 Oct 2012 17:52:09 +1100 Subject: [PATCH 047/194] update changelog in prep for 1.2 --- CHANGELOG.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f2d66ba..9e97469c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.2 (Unreleased) ## +## 1.2 (2012-10-13) ## * Allow alternate redis database to be selected when calling setBackend by supplying a second argument (patrickbajao) * Use `require_once` when including php-resque after the app has been included in the sample resque.php to prevent include conflicts (andrewjshults) @@ -10,7 +10,16 @@ * Fix lost jobs when there is more than one worker process started by the same parent process (salimane) * Move include for resque before APP_INCLUDE is loaded in, so that way resque is available for the app * Avoid working with dirty worker IDs (salimane) - +* Allow UNIX socket to be passed to Resque when connecting to Redis (pedroarnal) +* Fix typographical errors in PHP docblocks (chaitanyakuber) +* Set the queue name on job instances when jobs are executed (chaitanyakuber) +* Fix and add tests for Resque_Event::stopListening (ebernhardson) +* Documentation cleanup (maetl) +* Pass queue name to afterEvent callback +* Only declare RedisException if it doesn't already exist (Matt Heath) +* Add support for Composer +* Fix missing and incorrect paths for Resque and Resque_Job_Status classes in demo (jjfrey) +* Disable autoload for the RedisException class_exists call (scragg0x) ## 1.1 (2011-03-27) ## From c908109a746f03abdb7a23a54dcf2e17694ca28d Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 13 Oct 2012 17:55:41 +1100 Subject: [PATCH 048/194] Remove silly copyright line in docblock comments, update email address, remove copyright year because it is boring to maintain --- LICENSE | 2 +- lib/Resque.php | 3 +-- lib/Resque/Event.php | 3 +-- lib/Resque/Exception.php | 3 +-- lib/Resque/Failure.php | 3 +-- lib/Resque/Failure/Interface.php | 3 +-- lib/Resque/Failure/Redis.php | 3 +-- lib/Resque/Job.php | 3 +-- lib/Resque/Job/DirtyExitException.php | 3 +-- lib/Resque/Job/DontPerform.php | 3 +-- lib/Resque/Job/Status.php | 3 +-- lib/Resque/Redis.php | 3 +-- lib/Resque/RedisCluster.php | 3 +-- lib/Resque/Stat.php | 3 +-- lib/Resque/Worker.php | 3 +-- test/Resque/Tests/EventTest.php | 3 +-- test/Resque/Tests/JobStatusTest.php | 3 +-- test/Resque/Tests/JobTest.php | 3 +-- test/Resque/Tests/StatTest.php | 3 +-- test/Resque/Tests/TestCase.php | 3 +-- test/Resque/Tests/WorkerTest.php | 3 +-- test/Resque/Tests/bootstrap.php | 3 +-- 22 files changed, 22 insertions(+), 43 deletions(-) diff --git a/LICENSE b/LICENSE index 65135912..a796ebf9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -(c) 2010 Chris Boulton +(c) Chris Boulton Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/lib/Resque.php b/lib/Resque.php index 9bc81431..5362b5b1 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -6,8 +6,7 @@ * Base Resque class. * * @package Resque - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque diff --git a/lib/Resque/Event.php b/lib/Resque/Event.php index 930c0671..20072ff9 100644 --- a/lib/Resque/Event.php +++ b/lib/Resque/Event.php @@ -3,8 +3,7 @@ * Resque event/plugin system class * * @package Resque/Event - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Event diff --git a/lib/Resque/Exception.php b/lib/Resque/Exception.php index b288bf47..60cca86f 100644 --- a/lib/Resque/Exception.php +++ b/lib/Resque/Exception.php @@ -3,8 +3,7 @@ * Resque exception. * * @package Resque - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Exception extends Exception diff --git a/lib/Resque/Failure.php b/lib/Resque/Failure.php index 9f6d89a7..e0c28a34 100644 --- a/lib/Resque/Failure.php +++ b/lib/Resque/Failure.php @@ -5,8 +5,7 @@ * Failed Resque job. * * @package Resque/Failure - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Failure diff --git a/lib/Resque/Failure/Interface.php b/lib/Resque/Failure/Interface.php index 863cd0b1..b7e5bc83 100644 --- a/lib/Resque/Failure/Interface.php +++ b/lib/Resque/Failure/Interface.php @@ -3,8 +3,7 @@ * Interface that all failure backends should implement. * * @package Resque/Failure - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ interface Resque_Failure_Interface diff --git a/lib/Resque/Failure/Redis.php b/lib/Resque/Failure/Redis.php index c81bfc20..cfac5b6c 100644 --- a/lib/Resque/Failure/Redis.php +++ b/lib/Resque/Failure/Redis.php @@ -3,8 +3,7 @@ * Redis backend for storing failed Resque jobs. * * @package Resque/Failure - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 0d275a12..661bd3c1 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -7,8 +7,7 @@ * Resque job. * * @package Resque/Job - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Job diff --git a/lib/Resque/Job/DirtyExitException.php b/lib/Resque/Job/DirtyExitException.php index b69413a3..108e0613 100644 --- a/lib/Resque/Job/DirtyExitException.php +++ b/lib/Resque/Job/DirtyExitException.php @@ -3,8 +3,7 @@ * Runtime exception class for a job that does not exit cleanly. * * @package Resque/Job - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Job_DirtyExitException extends RuntimeException diff --git a/lib/Resque/Job/DontPerform.php b/lib/Resque/Job/DontPerform.php index 91d5c70e..553327ff 100644 --- a/lib/Resque/Job/DontPerform.php +++ b/lib/Resque/Job/DontPerform.php @@ -3,8 +3,7 @@ * Exception to be thrown if a job should not be performed/run. * * @package Resque/Job - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Job_DontPerform extends Exception diff --git a/lib/Resque/Job/Status.php b/lib/Resque/Job/Status.php index e1554b02..ffa351ba 100644 --- a/lib/Resque/Job/Status.php +++ b/lib/Resque/Job/Status.php @@ -3,8 +3,7 @@ * Status tracker/information for a job. * * @package Resque/Job - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Job_Status diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index b6d7522d..053f2f90 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -10,8 +10,7 @@ * redis. Essentially adds namespace support to Redisent. * * @package Resque/Redis - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Redis extends Redisent diff --git a/lib/Resque/RedisCluster.php b/lib/Resque/RedisCluster.php index 39c3f5c6..100bdb70 100644 --- a/lib/Resque/RedisCluster.php +++ b/lib/Resque/RedisCluster.php @@ -10,8 +10,7 @@ * redis. Essentially adds namespace support to Redisent. * * @package Resque/Redis - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_RedisCluster extends RedisentCluster diff --git a/lib/Resque/Stat.php b/lib/Resque/Stat.php index 2805376c..bc00c636 100644 --- a/lib/Resque/Stat.php +++ b/lib/Resque/Stat.php @@ -3,8 +3,7 @@ * Resque statistic management (jobs processed, failed, etc) * * @package Resque/Stat - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Stat diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 31f2f3ca..5aa1ccdb 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -9,8 +9,7 @@ * off the queues, running them and handling the result. * * @package Resque/Worker - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Worker diff --git a/test/Resque/Tests/EventTest.php b/test/Resque/Tests/EventTest.php index 0bf5ee95..f53f2eb1 100644 --- a/test/Resque/Tests/EventTest.php +++ b/test/Resque/Tests/EventTest.php @@ -5,8 +5,7 @@ * Resque_Event tests. * * @package Resque/Tests - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Tests_EventTest extends Resque_Tests_TestCase diff --git a/test/Resque/Tests/JobStatusTest.php b/test/Resque/Tests/JobStatusTest.php index 5f0fd0f9..61f09b14 100644 --- a/test/Resque/Tests/JobStatusTest.php +++ b/test/Resque/Tests/JobStatusTest.php @@ -5,8 +5,7 @@ * Resque_Job_Status tests. * * @package Resque/Tests - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Tests_JobStatusTest extends Resque_Tests_TestCase diff --git a/test/Resque/Tests/JobTest.php b/test/Resque/Tests/JobTest.php index 31022912..572c51b7 100644 --- a/test/Resque/Tests/JobTest.php +++ b/test/Resque/Tests/JobTest.php @@ -5,8 +5,7 @@ * Resque_Job tests. * * @package Resque/Tests - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Tests_JobTest extends Resque_Tests_TestCase diff --git a/test/Resque/Tests/StatTest.php b/test/Resque/Tests/StatTest.php index 64047948..167633cc 100644 --- a/test/Resque/Tests/StatTest.php +++ b/test/Resque/Tests/StatTest.php @@ -5,8 +5,7 @@ * Resque_Stat tests. * * @package Resque/Tests - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Tests_StatTest extends Resque_Tests_TestCase diff --git a/test/Resque/Tests/TestCase.php b/test/Resque/Tests/TestCase.php index f4c00dfa..6c052d3c 100644 --- a/test/Resque/Tests/TestCase.php +++ b/test/Resque/Tests/TestCase.php @@ -3,8 +3,7 @@ * Resque test case class. Contains setup and teardown methods. * * @package Resque/Tests - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Tests_TestCase extends PHPUnit_Framework_TestCase diff --git a/test/Resque/Tests/WorkerTest.php b/test/Resque/Tests/WorkerTest.php index 47b02081..f6199af9 100644 --- a/test/Resque/Tests/WorkerTest.php +++ b/test/Resque/Tests/WorkerTest.php @@ -5,8 +5,7 @@ * Resque_Worker tests. * * @package Resque/Tests - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ class Resque_Tests_WorkerTest extends Resque_Tests_TestCase diff --git a/test/Resque/Tests/bootstrap.php b/test/Resque/Tests/bootstrap.php index 0efa2a84..7671e437 100644 --- a/test/Resque/Tests/bootstrap.php +++ b/test/Resque/Tests/bootstrap.php @@ -3,8 +3,7 @@ * Resque test bootstrap file - sets up a test environment. * * @package Resque/Tests - * @author Chris Boulton - * @copyright (c) 2010 Chris Boulton + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ define('CWD', dirname(__FILE__)); From 02141982b1914caea7b0a3e15e69ac704b574dfd Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 13 Oct 2012 17:58:42 +1100 Subject: [PATCH 049/194] remove bin/resque, which is empty --- bin/resque | 1 - 1 file changed, 1 deletion(-) delete mode 100644 bin/resque diff --git a/bin/resque b/bin/resque deleted file mode 100644 index 1a248525..00000000 --- a/bin/resque +++ /dev/null @@ -1 +0,0 @@ -#!/bin/sh From aeb0ddcf0820e7738d4d689a36a98806732bf57f Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 13 Oct 2012 17:59:01 +1100 Subject: [PATCH 050/194] update changelog to mention changes coming to php-resque --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e97469c..f3b5e9f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ * Add support for Composer * Fix missing and incorrect paths for Resque and Resque_Job_Status classes in demo (jjfrey) * Disable autoload for the RedisException class_exists call (scragg0x) +* General tidyup of comments and files/folders ## 1.1 (2011-03-27) ## From 8d05f92a22f21ac7a032db3c7ab168d978031967 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 13 Oct 2012 18:10:53 +1100 Subject: [PATCH 051/194] remove old TODO file --- TODO.md | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 TODO.md diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 61ea867d..00000000 --- a/TODO.md +++ /dev/null @@ -1,8 +0,0 @@ -* Write tests for: - * `Resque_Failure` - * `Resque_Failure_Redis` -* Change to preforking worker model -* Clean up /bin and /demo -* Add a way to store arbitrary text in job statuses (for things like progress -indicators) -* Write plugin for Ruby resque that calls setUp and tearDown methods \ No newline at end of file From d055a7e00bd2869ec95bf94f78708e19c9926871 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 13 Oct 2012 18:21:20 +1100 Subject: [PATCH 052/194] add note about future backwards compatibility --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3b5e9f9..2992de8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## 1.2 (2012-10-13) ## +**Note:** This release is largely backwards compatible with php-resque 1.1. The next release will introduce backwards incompatible changes (moving from Redisent to Credis), and will drop compatibility with PHP 5.2. + * Allow alternate redis database to be selected when calling setBackend by supplying a second argument (patrickbajao) * Use `require_once` when including php-resque after the app has been included in the sample resque.php to prevent include conflicts (andrewjshults) * Wrap job arguments in an array to improve compatibility with ruby resque (warezthebeef) From bf91b4cc6b793c3317dbe0b4659a756c06e7937a Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 13 Oct 2012 18:23:06 +1100 Subject: [PATCH 053/194] update contributors --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 2f942ab9..afc8956f 100644 --- a/README.md +++ b/README.md @@ -329,3 +329,16 @@ Called after a job has been queued using the `Resque::enqueue` method. Arguments * KevBurnsJr * jmathai * dceballos +* patrickbajao +* andrewjshults +* warezthebeef +* d11wtq +* hlegius +* salimane +* humancopy +* pedroarnal +* chaitanyakuber +* maetl +* Matt Heath +* jjfrey +* scragg0x \ No newline at end of file From 0549d6c88a4aed934655b7c03b6153349d6c3ad0 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 13 Oct 2012 18:28:16 +1100 Subject: [PATCH 054/194] update version to 1.2 --- lib/Resque.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque.php b/lib/Resque.php index 5362b5b1..a3150cb1 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -11,7 +11,7 @@ */ class Resque { - const VERSION = '1.0'; + const VERSION = '1.2'; /** * @var Resque_Redis Instance of Resque_Redis that talks to redis. From 3314d407eba016c8c3e932040475691f95ef8a20 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 13 Oct 2012 18:32:05 +1100 Subject: [PATCH 055/194] stop testing on php 5.2 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1284d21c..625062e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ language: php php: - - 5.2 - 5.3 - 5.4 From 3955bc8edc410c68c57e44120b709465101e090a Mon Sep 17 00:00:00 2001 From: Allen Torres Date: Thu, 1 Nov 2012 09:28:47 -0400 Subject: [PATCH 056/194] Updated recreate method in Resque_Job class to set arguments in the same fashion as getAruments returns them. --- lib/Resque/Job.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 661bd3c1..e673c4f7 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -231,7 +231,7 @@ public function recreate() $monitor = true; } - return self::create($this->queue, $this->payload['class'], $this->payload['args'], $monitor); + return self::create($this->queue, $this->payload['class'], $this->payload['args'][0], $monitor); } /** From f6334bb3b89a604e36440065b36e0de6ac96207a Mon Sep 17 00:00:00 2001 From: Allen Torres Date: Thu, 1 Nov 2012 09:37:06 -0400 Subject: [PATCH 057/194] Added a check to see if we have args before we attempt to access the first item in the payload args to prevent an undefined index error. --- lib/Resque/Job.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index e673c4f7..0e03f04d 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -230,8 +230,9 @@ public function recreate() if($status->isTracking()) { $monitor = true; } - - return self::create($this->queue, $this->payload['class'], $this->payload['args'][0], $monitor); + $args = count($this->payload['args'])? $this->payload['args'][0] : $this->payload['args']; + + return self::create($this->queue, $this->payload['class'], $args, $monitor); } /** From 7f1cf35a62d92327f20f7b752e219c50d5fef9a0 Mon Sep 17 00:00:00 2001 From: Tony Piper Date: Mon, 26 Nov 2012 15:23:57 +0000 Subject: [PATCH 058/194] implement prefix removel --- lib/Resque/Redis.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 053f2f90..5e18a015 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -113,5 +113,20 @@ public function __call($name, $args) { return false; } } + + public static function getPrefix() + { + return self::$defaultNamespace; + } + + public static function removePrefix($string) + { + $prefix=self::getPrefix(); + + if (substr($string, 0, strlen($prefix)) == $prefix) { + $string = substr($string, strlen($prefix), strlen($string) ); + } + return $string; + } } ?> \ No newline at end of file From e4f39a60931e68e83d963c44d8c42615ec70f188 Mon Sep 17 00:00:00 2001 From: Allen Torres Date: Fri, 28 Dec 2012 09:33:09 -0500 Subject: [PATCH 059/194] Updated Redisent.php to attempt three reconnects to the redis server before giving up. Also supressed fwrite errors. --- lib/Redisent/Redisent.php | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/Redisent/Redisent.php b/lib/Redisent/Redisent.php index 4b480f66..727f16b2 100644 --- a/lib/Redisent/Redisent.php +++ b/lib/Redisent/Redisent.php @@ -43,6 +43,13 @@ class Redisent { * @access public */ public $port; + + /** + * Number of times to attempt a reconnect + * + * @var int + */ + public $max_reconnects = 3; /** * Creates a Redisent connection to the Redis server on host {@link $host} and port {@link $port}. @@ -73,10 +80,17 @@ function __call($name, $args) { $command = sprintf('*%d%s%s%s', count($args), CRLF, implode(array_map(array($this, 'formatArgument'), $args), CRLF), CRLF); /* Open a Redis connection and execute the command */ + $reconnects = 0; for ($written = 0; $written < strlen($command); $written += $fwrite) { - $fwrite = fwrite($this->__sock, substr($command, $written)); - if ($fwrite === FALSE) { - throw new Exception('Failed to write entire command to stream'); + $fwrite = @fwrite($this->__sock, substr($command, $written)); + if ($fwrite === FALSE || $fwrite === 0) { + if ($reconnects >= (int)$this->max_reconnects) { + throw new Exception('Failed to write entire command to stream'); + }else{ + fclose($this->__sock); + $this->establishConnection(); + $reconnects++; + } } } From 0afb87663f113cd09d411621beb7c7b72bc89253 Mon Sep 17 00:00:00 2001 From: Allen Torres Date: Fri, 28 Dec 2012 10:33:32 -0500 Subject: [PATCH 060/194] Reverted changes made to upstream master. --- lib/Resque/Job.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 0e03f04d..e673c4f7 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -230,9 +230,8 @@ public function recreate() if($status->isTracking()) { $monitor = true; } - $args = count($this->payload['args'])? $this->payload['args'][0] : $this->payload['args']; - - return self::create($this->queue, $this->payload['class'], $args, $monitor); + + return self::create($this->queue, $this->payload['class'], $this->payload['args'][0], $monitor); } /** From a5b70a5cbd087f2b2c697a698a8ff64074535203 Mon Sep 17 00:00:00 2001 From: Allen Torres Date: Fri, 28 Dec 2012 10:39:34 -0500 Subject: [PATCH 061/194] Added a sleep call for a second before establishing another connection. --- lib/Redisent/Redisent.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Redisent/Redisent.php b/lib/Redisent/Redisent.php index 727f16b2..92ccd026 100644 --- a/lib/Redisent/Redisent.php +++ b/lib/Redisent/Redisent.php @@ -88,6 +88,7 @@ function __call($name, $args) { throw new Exception('Failed to write entire command to stream'); }else{ fclose($this->__sock); + sleep(1); $this->establishConnection(); $reconnects++; } From fdc9f881e8b40cdb4a3fdb540ac1afdce0a0ca2f Mon Sep 17 00:00:00 2001 From: Allen Torres Date: Fri, 28 Dec 2012 10:42:16 -0500 Subject: [PATCH 062/194] Reverted changes made from upstream master. --- lib/Resque/Job.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index e673c4f7..661bd3c1 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -231,7 +231,7 @@ public function recreate() $monitor = true; } - return self::create($this->queue, $this->payload['class'], $this->payload['args'][0], $monitor); + return self::create($this->queue, $this->payload['class'], $this->payload['args'], $monitor); } /** From 5127aefa904773de899dfe1394bbcc3bbd0196fd Mon Sep 17 00:00:00 2001 From: Daniel Hunsaker Date: Fri, 11 Jan 2013 13:40:39 -0700 Subject: [PATCH 063/194] Update lib/Resque/Redis.php Add SETEX to the list of commands which supply a key as the first argument. --- lib/Resque/Redis.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 5e18a015..dcfc47d8 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -33,6 +33,7 @@ class Resque_Redis extends Redisent 'ttl', 'move', 'set', + 'setex', 'get', 'getset', 'setnx', @@ -129,4 +130,4 @@ public static function removePrefix($string) return $string; } } -?> \ No newline at end of file +?> From e72c31a4501e6b207ec3c38e569b1dec6d3a8a83 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 12 Jan 2013 21:45:06 +1100 Subject: [PATCH 064/194] ignore vendor/ --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a725465a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +vendor/ \ No newline at end of file From 8a7f11f906d4e692666396bb33ac250e07a7e807 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 12 Jan 2013 21:47:07 +1100 Subject: [PATCH 065/194] add phpunit as a development requirement --- composer.json | 3 + composer.lock | 408 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 411 insertions(+) create mode 100644 composer.lock diff --git a/composer.json b/composer.json index 594f13ff..79d3840d 100644 --- a/composer.json +++ b/composer.json @@ -14,6 +14,9 @@ "require": { "php": ">=5.3.0" }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, "autoload": { "psr-0": { "Resque": "lib" diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000..64c1bceb --- /dev/null +++ b/composer.lock @@ -0,0 +1,408 @@ +{ + "hash": "3df3cf88489d7751f032e8205ebcda7c", + "packages": [ + + ], + "packages-dev": [ + { + "name": "phpunit/php-code-coverage", + "version": "1.2.7", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "1.2.7" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-code-coverage/archive/1.2.7.zip", + "reference": "1.2.7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": ">=1.3.0@stable", + "phpunit/php-token-stream": ">=1.1.3@stable", + "phpunit/php-text-template": ">=1.1.1@stable" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.0.5" + }, + "time": "2012-12-02 14:54:55", + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "testing", + "coverage", + "xunit" + ] + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.3.3", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "1.3.3" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-file-iterator/zipball/1.3.3", + "reference": "1.3.3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "time": "2012-10-11 04:44:38", + "type": "library", + "autoload": { + "classmap": [ + "File/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "filesystem", + "iterator" + ] + }, + { + "name": "phpunit/php-text-template", + "version": "1.1.4", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-text-template.git", + "reference": "1.1.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-text-template/zipball/1.1.4", + "reference": "1.1.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "time": "2012-10-31 11:15:28", + "type": "library", + "autoload": { + "classmap": [ + "Text/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ] + }, + { + "name": "phpunit/php-timer", + "version": "1.0.4", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-timer.git", + "reference": "1.0.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-timer/zipball/1.0.4", + "reference": "1.0.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "time": "2012-10-11 04:45:58", + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "timer" + ] + }, + { + "name": "phpunit/php-token-stream", + "version": "1.1.5", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-token-stream.git", + "reference": "1.1.5" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-token-stream/zipball/1.1.5", + "reference": "1.1.5", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "time": "2012-10-11 04:47:14", + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "tokenizer" + ] + }, + { + "name": "phpunit/phpunit", + "version": "3.7.12", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/phpunit.git", + "reference": "3.7.12" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/phpunit/archive/3.7.12.zip", + "reference": "3.7.12", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": ">=1.3.1", + "phpunit/php-text-template": ">=1.1.1", + "phpunit/php-code-coverage": ">=1.2.1", + "phpunit/php-timer": ">=1.0.2", + "phpunit/phpunit-mock-objects": ">=1.2.0,<1.3.0", + "symfony/yaml": ">=2.1.0,<2.2.0", + "ext-dom": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*" + }, + "suggest": { + "phpunit/php-invoker": ">=1.1.0", + "ext-json": "*", + "ext-simplexml": "*", + "ext-tokenizer": "*" + }, + "time": "2013-01-09 22:41:02", + "bin": [ + "composer/bin/phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "", + "../../symfony/yaml/" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "testing", + "phpunit", + "xunit" + ] + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "1.2.2", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "1.2.2" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects/archive/1.2.2.zip", + "reference": "1.2.2", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-text-template": ">=1.1.1@stable" + }, + "suggest": { + "ext-soap": "*" + }, + "time": "2012-11-05 10:39:13", + "type": "library", + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ] + }, + { + "name": "symfony/yaml", + "version": "v2.1.6", + "target-dir": "Symfony/Component/Yaml", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml", + "reference": "v2.1.6" + }, + "dist": { + "type": "zip", + "url": "https://github.com/symfony/Yaml/archive/v2.1.6.zip", + "reference": "v2.1.6", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "time": "2012-12-06 10:00:55", + "type": "library", + "autoload": { + "psr-0": { + "Symfony\\Component\\Yaml": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "http://symfony.com/" + } + ], + "aliases": [ + + ], + "minimum-stability": "stable", + "stability-flags": [ + + ] +} From 8d6da214732179b223252f3bcb21ece9558f2af0 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 12 Jan 2013 22:01:13 +1100 Subject: [PATCH 066/194] restructure tests, use composer to autoload test requirements --- .travis.yml | 2 ++ phpunit.xml | 3 ++- test/Resque/Tests/EventTest.php | 2 -- test/Resque/Tests/JobStatusTest.php | 2 -- test/Resque/Tests/JobTest.php | 1 - test/Resque/Tests/StatTest.php | 2 -- test/Resque/Tests/WorkerTest.php | 2 -- test/{Resque/Tests => }/bootstrap.php | 19 +++++-------------- 8 files changed, 9 insertions(+), 24 deletions(-) rename test/{Resque/Tests => }/bootstrap.php (86%) diff --git a/.travis.yml b/.travis.yml index 625062e4..b1b8e8c8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,3 +2,5 @@ language: php php: - 5.3 - 5.4 +before_script: + - composer install --dev \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml index efbc7f29..61d2d7b3 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,7 +1,8 @@ * @license http://www.opensource.org/licenses/mit-license.php */ -define('CWD', dirname(__FILE__)); -define('RESQUE_LIB', CWD . '/../../../lib/'); -define('TEST_MISC', realpath(CWD . '/../../misc/')); -define('REDIS_CONF', TEST_MISC . '/redis.conf'); - -// Change to the directory this file lives in. This is important, due to -// how we'll be running redis. - -require_once CWD . '/TestCase.php'; +$loader = require __DIR__ . '/../vendor/autoload.php'; +$loader->add('Resque_Tests', __DIR__); -// Include Resque -require_once RESQUE_LIB . 'Resque.php'; -require_once RESQUE_LIB . 'Resque/Worker.php'; -require_once RESQUE_LIB . 'Resque/Redis.php'; +define('TEST_MISC', realpath(__DIR__ . '/misc/')); +define('REDIS_CONF', TEST_MISC . '/redis.conf'); // Attempt to start our own redis instance for tesitng. exec('which redis-server', $output, $returnVar); @@ -61,7 +52,7 @@ function killRedis($pid) if (file_exists($pidFile)) { $pid = trim(file_get_contents($pidFile)); posix_kill((int) $pid, 9); - + if(is_file($pidFile)) { unlink($pidFile); } From 2f5b48930f7fcc51931d608b2d37897a350a7eea Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 12 Jan 2013 22:40:26 +1100 Subject: [PATCH 067/194] make better use of composer across php-resque * recommend php-resque be installed via Composer * provide quick getting started steps * move ./resque.php to bin/resque, make it available as a Composer bin * have classes autoloaded via Composer (or some other means if not using Composer) --- README.md | 57 ++++++++++++++++++++++++++++++---------- resque.php => bin/resque | 30 ++++++++++++++++++--- composer.json | 3 +++ composer.lock | 2 +- demo/check_status.php | 4 +-- demo/init.php | 25 ++++++++++++++++++ demo/queue.php | 2 +- demo/resque.php | 2 +- extras/resque.monit | 2 +- lib/Resque.php | 7 ----- lib/Resque/Failure.php | 2 -- lib/Resque/Job.php | 5 ---- lib/Resque/Worker.php | 5 ---- 13 files changed, 103 insertions(+), 43 deletions(-) rename resque.php => bin/resque (74%) create mode 100644 demo/init.php diff --git a/README.md b/README.md index afc8956f..231aebaf 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,32 @@ pre and post jobs * PHP 5.2+ * Redis 2.2+ +* Optional but Recommended: Composer + +## Getting Started ## + +The easiest way to work with php-resque is when it's installed as a +Composer package inside your project. Composer isn't strictly +required, but makes life a lot easier. + +If you're not familiar with Composer, please see . + +1. Add php-resque to your application's composer.json. + + { + ... + "require": { + "php": ">=5.3.0" + }, + ... + } + +2. Run `composer install`. + +3. If you haven't already, add the Composer autoload to your project's + initialization file. (example) + + require 'vendor/autoload.php'; ## Jobs ## @@ -46,8 +72,6 @@ pre and post jobs Jobs are queued as follows: - require_once 'lib/Resque.php'; - // Required if redis is located elsewhere Resque::setBackend('localhost:6379'); @@ -87,12 +111,12 @@ The `tearDown` method if defined, will be called after the job finishes. { // ... Set up environment for this job } - + public function perform() { // .. Run job } - + public function tearDown() { // ... Remove environment for this job @@ -136,8 +160,9 @@ class. Workers work in the exact same way as the Ruby workers. For complete documentation on workers, see the original documentation. -A basic "up-and-running" resque.php file is included that sets up a -running worker environment is included in the root directory. +A basic "up-and-running" `bin/resque` file is included that sets up a +running worker environment is included. (`vendor/bin/resque` when installed +via Composer) The exception to the similarities with the Ruby version of resque is how a worker is initially setup. To work under all environments, @@ -146,13 +171,17 @@ not having a single environment such as with Ruby, the PHP port makes To start a worker, it's very similar to the Ruby version: - $ QUEUE=file_serve php resque.php + $ QUEUE=file_serve php bin/resque It's your responsibility to tell the worker which file to include to get your application underway. You do so by setting the `APP_INCLUDE` environment variable: - $ QUEUE=file_serve APP_INCLUDE=../application/init.php php resque.php + $ QUEUE=file_serve APP_INCLUDE=../application/init.php php bin/resque + +*Pro tip: Using Composer? More than likely, you don't need to worry about +`APP_INCLUDE`, because hopefully Composer is responsible for autoloading +your application too!* Getting your application underway also includes telling the worker your job classes, by means of either an autoloader or including them. @@ -163,8 +192,8 @@ The port supports the same environment variables for logging to STDOUT. Setting `VERBOSE` will print basic debugging information and `VVERBOSE` will print detailed information. - $ VERBOSE QUEUE=file_serve php resque.php - $ VVERBOSE QUEUE=file_serve php resque.php + $ VERBOSE QUEUE=file_serve bin/resque + $ VVERBOSE QUEUE=file_serve bin/resque ### Priorities and Queue Lists ### @@ -175,7 +204,7 @@ checked in. As per the original example: - $ QUEUE=file_serve,warm_cache php resque.php + $ QUEUE=file_serve,warm_cache bin/resque The `file_serve` queue will always be checked for new jobs on each iteration before the `warm_cache` queue is checked. @@ -185,14 +214,14 @@ iteration before the `warm_cache` queue is checked. All queues are supported in the same manner and processed in alphabetical order: - $ QUEUE=* php resque.php + $ QUEUE=* bin/resque ### Running Multiple Workers ### Multiple workers ca be launched and automatically worked by supplying the `COUNT` environment variable: - $ COUNT=5 php resque.php + $ COUNT=5 bin/resque ### Forking ### @@ -257,7 +286,7 @@ It is up to your application to register event listeners. When enqueuing events in your application, it should be as easy as making sure php-resque is loaded and calling `Resque_Event::listen`. -When running workers, if you run workers via the default `resque.php` script, +When running workers, if you run workers via the default `bin/resque` script, your `APP_INCLUDE` script should initialize and register any listeners required for operation. If you have rolled your own worker manager, then it is again your responsibility to register listeners. diff --git a/resque.php b/bin/resque similarity index 74% rename from resque.php rename to bin/resque index 02ecc1ab..687f6c40 100644 --- a/resque.php +++ b/bin/resque @@ -1,12 +1,34 @@ +#!/usr/bin/env php logLevel = $logLevel; - + $PIDFILE = getenv('PIDFILE'); if ($PIDFILE) { file_put_contents($PIDFILE, getmypid()) or diff --git a/composer.json b/composer.json index 79d3840d..a3880ae5 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,9 @@ "require-dev": { "phpunit/phpunit": "3.7.*" }, + "bin": [ + "bin/resque" + ], "autoload": { "psr-0": { "Resque": "lib" diff --git a/composer.lock b/composer.lock index 64c1bceb..91301f74 100644 --- a/composer.lock +++ b/composer.lock @@ -1,5 +1,5 @@ { - "hash": "3df3cf88489d7751f032e8205ebcda7c", + "hash": "b05c2c31be6cac834e33b1a7fe61d063", "packages": [ ], diff --git a/demo/check_status.php b/demo/check_status.php index c1959114..061a83a9 100644 --- a/demo/check_status.php +++ b/demo/check_status.php @@ -3,8 +3,8 @@ die('Specify the ID of a job to monitor the status of.'); } -require '../lib/Resque/Job/Status.php'; -require '../lib/Resque.php'; +require __DIR__ . '/init.php'; + date_default_timezone_set('GMT'); Resque::setBackend('127.0.0.1:6379'); diff --git a/demo/init.php b/demo/init.php new file mode 100644 index 00000000..9078bcda --- /dev/null +++ b/demo/init.php @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/extras/resque.monit b/extras/resque.monit index 654815da..b611f8f5 100644 --- a/extras/resque.monit +++ b/extras/resque.monit @@ -9,7 +9,7 @@ check process resque_worker_[QUEUE] with pidfile /var/run/resque/worker_[QUEUE].pid - start program = "/bin/sh -c 'APP_INCLUDE=[APP_INCLUDE] QUEUE=[QUEUE] VERBOSE=1 PIDFILE=/var/run/resque/worker_[QUEUE].pid nohup php -f [PATH/TO/RESQUE]/resque.php > /var/log/resque/worker_[QUEUE].log &'" as uid [UID] and gid [GID] + start program = "/bin/sh -c 'APP_INCLUDE=[APP_INCLUDE] QUEUE=[QUEUE] VERBOSE=1 PIDFILE=/var/run/resque/worker_[QUEUE].pid nohup php -f [PATH/TO/RESQUE]/bin/resque > /var/log/resque/worker_[QUEUE].log &'" as uid [UID] and gid [GID] stop program = "/bin/sh -c 'kill -s QUIT `cat /var/run/resque/worker_[QUEUE].pid` && rm -f /var/run/resque/worker_[QUEUE].pid; exit 0;'" if totalmem is greater than 300 MB for 10 cycles then restart # eating up memory? group resque_workers \ No newline at end of file diff --git a/lib/Resque.php b/lib/Resque.php index a3150cb1..c3254a36 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -1,7 +1,4 @@ updateStatus(Resque_Job_Status::STATUS_FAILED); - require_once dirname(__FILE__) . '/Failure.php'; Resque_Failure::create( $this->payload, $exception, diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 5aa1ccdb..d103810a 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -1,9 +1,4 @@ Date: Sat, 12 Jan 2013 22:54:42 +1100 Subject: [PATCH 068/194] update changelog --- CHANGELOG.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2992de8e..0e27544f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +## 1.3 (2013-??-??) - Current Master ## + +**Note:** This release introduces backwards incompatible changes with all previous versions of php-resque. Please see below for details. + +### Composer Support + +Composer support has been improved and is now the recommended method for including php-resque in your project. Details on Composer support can be found in the Getting Started section of the readme. + +### Other Improvements/Changes + +* **COMPATIBILITY BREAKING**: The bundled worker manager `resque.php` has been moved to `bin/resque`, and is available as `vendor/bin/resque` when php-resque is installed as a Composer package. + +* Restructure tests and test bootstrapping. Autoload tests via Composer (install test dependencies with `composer install --dev`) + +* Add `SETEX` to list of commands which supply a key as the first argument in Redisent (danhunsaker) + +* Fix an issue where a lost connection to Redis could cause an infinite loop (atorres757) + +* Add a helper method to `Resque_Redis` to remove the namespace applied to Redis keys (tonypiper) + + ## 1.2 (2012-10-13) ## **Note:** This release is largely backwards compatible with php-resque 1.1. The next release will introduce backwards incompatible changes (moving from Redisent to Credis), and will drop compatibility with PHP 5.2. @@ -22,7 +43,7 @@ * Add support for Composer * Fix missing and incorrect paths for Resque and Resque_Job_Status classes in demo (jjfrey) * Disable autoload for the RedisException class_exists call (scragg0x) -* General tidyup of comments and files/folders +* General tidy up of comments and files/folders ## 1.1 (2011-03-27) ## From a77699549bb51e5b00f7fd8f17860faec727657f Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 12 Jan 2013 23:06:55 +1100 Subject: [PATCH 069/194] bump php requirement up to 5.3 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 231aebaf..2b94eac9 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ pre and post jobs ## Requirements ## -* PHP 5.2+ +* PHP 5.3+ * Redis 2.2+ * Optional but Recommended: Composer From a6eb8e1c45875f8e8a809fd2ed38b6f55c90c626 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 12 Jan 2013 23:07:15 +1100 Subject: [PATCH 070/194] use __DIR__ --- lib/Redisent/RedisentCluster.php | 2 +- lib/Resque/Redis.php | 2 +- lib/Resque/RedisCluster.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Redisent/RedisentCluster.php b/lib/Redisent/RedisentCluster.php index ea936116..215726ee 100644 --- a/lib/Redisent/RedisentCluster.php +++ b/lib/Redisent/RedisentCluster.php @@ -7,7 +7,7 @@ * @package Redisent */ -require_once dirname(__FILE__) . '/Redisent.php'; +require_once __DIR__ . '/Redisent.php'; /** * A generalized Redisent interface for a cluster of Redis servers diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index dcfc47d8..1cff624c 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -2,7 +2,7 @@ // Third- party apps may have already loaded Resident from elsewhere // so lets be careful. if(!class_exists('Redisent', false)) { - require_once dirname(__FILE__) . '/../Redisent/Redisent.php'; + require_once __DIR__ . '/../Redisent/Redisent.php'; } /** diff --git a/lib/Resque/RedisCluster.php b/lib/Resque/RedisCluster.php index 100bdb70..21caeb77 100644 --- a/lib/Resque/RedisCluster.php +++ b/lib/Resque/RedisCluster.php @@ -2,7 +2,7 @@ // Third- party apps may have already loaded Resident from elsewhere // so lets be careful. if(!class_exists('RedisentCluster', false)) { - require_once dirname(__FILE__) . '/../Redisent/RedisentCluster.php'; + require_once __DIR__ . '/../Redisent/RedisentCluster.php'; } /** From 2ba15eb555b5cda349b0211b11bb70883f27af25 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 12 Jan 2013 23:37:38 +1100 Subject: [PATCH 071/194] replace Redisent with Credis (also adds native phpredis support) --- CHANGELOG.md | 8 + composer.json | 9 +- composer.lock | 399 ++----------------------------- lib/Redisent/LICENSE | 22 -- lib/Redisent/README.markdown | 67 ------ lib/Redisent/Redisent.php | 165 ------------- lib/Redisent/RedisentCluster.php | 138 ----------- lib/Resque.php | 16 +- lib/Resque/Redis.php | 57 +++-- lib/Resque/RedisCluster.php | 117 --------- test/Resque/Tests/TestCase.php | 2 +- 11 files changed, 81 insertions(+), 919 deletions(-) delete mode 100644 lib/Redisent/LICENSE delete mode 100644 lib/Redisent/README.markdown delete mode 100644 lib/Redisent/Redisent.php delete mode 100644 lib/Redisent/RedisentCluster.php delete mode 100644 lib/Resque/RedisCluster.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e27544f..f6f11965 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ **Note:** This release introduces backwards incompatible changes with all previous versions of php-resque. Please see below for details. +### Redisent (Redis Library) Replaced with Credis + +Redisent has always been the Redis backend for php-resque because of its lightweight nature. Unfortunately, Redisent is largely unmaintained. + +[Credis](http://example.com/) is a fork of Redisent, which among other improvements will automatically use the [phpredis](https://github.com/nicolasff/phpredis) native PHP extension if it is available. (you want this for speed, trust me) + +php-resque now utilizes Credis for all Redis based operations. Credis automatically required and installed as a Composer dependency. + ### Composer Support Composer support has been improved and is now the recommended method for including php-resque in your project. Details on Composer support can be found in the Getting Started section of the readme. diff --git a/composer.json b/composer.json index a3880ae5..9b67eaec 100644 --- a/composer.json +++ b/composer.json @@ -11,8 +11,15 @@ "email": "chris@bigcommerce.com" } ], + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/chrisboulton/credis" + } + ], "require": { - "php": ">=5.3.0" + "php": ">=5.3.0", + "colinmollenhour/credis": "dev-master" }, "require-dev": { "phpunit/phpunit": "3.7.*" diff --git a/composer.lock b/composer.lock index 91301f74..472226fd 100644 --- a/composer.lock +++ b/composer.lock @@ -1,408 +1,53 @@ { - "hash": "b05c2c31be6cac834e33b1a7fe61d063", + "hash": "af626b3a277bd0ab503c2c107327a88e", "packages": [ - - ], - "packages-dev": [ - { - "name": "phpunit/php-code-coverage", - "version": "1.2.7", - "source": { - "type": "git", - "url": "git://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "1.2.7" - }, - "dist": { - "type": "zip", - "url": "https://github.com/sebastianbergmann/php-code-coverage/archive/1.2.7.zip", - "reference": "1.2.7", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "phpunit/php-file-iterator": ">=1.3.0@stable", - "phpunit/php-token-stream": ">=1.1.3@stable", - "phpunit/php-text-template": ">=1.1.1@stable" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.0.5" - }, - "time": "2012-12-02 14:54:55", - "type": "library", - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "testing", - "coverage", - "xunit" - ] - }, - { - "name": "phpunit/php-file-iterator", - "version": "1.3.3", - "source": { - "type": "git", - "url": "git://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "1.3.3" - }, - "dist": { - "type": "zip", - "url": "https://github.com/sebastianbergmann/php-file-iterator/zipball/1.3.3", - "reference": "1.3.3", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "time": "2012-10-11 04:44:38", - "type": "library", - "autoload": { - "classmap": [ - "File/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "http://www.phpunit.de/", - "keywords": [ - "filesystem", - "iterator" - ] - }, { - "name": "phpunit/php-text-template", - "version": "1.1.4", + "name": "colinmollenhour/credis", + "version": "dev-master", "source": { "type": "git", - "url": "git://github.com/sebastianbergmann/php-text-template.git", - "reference": "1.1.4" + "url": "https://github.com/chrisboulton/credis", + "reference": "62c73dd16e08069e3fd8f224cb4a5ddd73db8095" }, "dist": { "type": "zip", - "url": "https://github.com/sebastianbergmann/php-text-template/zipball/1.1.4", - "reference": "1.1.4", + "url": "https://api.github.com/repos/chrisboulton/credis/zipball/62c73dd16e08069e3fd8f224cb4a5ddd73db8095", + "reference": "62c73dd16e08069e3fd8f224cb4a5ddd73db8095", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3.0" }, - "time": "2012-10-31 11:15:28", + "time": "2013-01-12 10:15:31", "type": "library", "autoload": { "classmap": [ - "Text/" + "Client.php", + "Cluster.php" ] }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ] - }, - { - "name": "phpunit/php-timer", - "version": "1.0.4", - "source": { - "type": "git", - "url": "git://github.com/sebastianbergmann/php-timer.git", - "reference": "1.0.4" - }, - "dist": { - "type": "zip", - "url": "https://github.com/sebastianbergmann/php-timer/zipball/1.0.4", - "reference": "1.0.4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "time": "2012-10-11 04:45:58", - "type": "library", - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "http://www.phpunit.de/", - "keywords": [ - "timer" - ] - }, - { - "name": "phpunit/php-token-stream", - "version": "1.1.5", - "source": { - "type": "git", - "url": "git://github.com/sebastianbergmann/php-token-stream.git", - "reference": "1.1.5" - }, - "dist": { - "type": "zip", - "url": "https://github.com/sebastianbergmann/php-token-stream/zipball/1.1.5", - "reference": "1.1.5", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" - }, - "time": "2012-10-11 04:47:14", - "type": "library", - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "http://www.phpunit.de/", - "keywords": [ - "tokenizer" - ] - }, - { - "name": "phpunit/phpunit", - "version": "3.7.12", - "source": { - "type": "git", - "url": "git://github.com/sebastianbergmann/phpunit.git", - "reference": "3.7.12" - }, - "dist": { - "type": "zip", - "url": "https://github.com/sebastianbergmann/phpunit/archive/3.7.12.zip", - "reference": "3.7.12", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "phpunit/php-file-iterator": ">=1.3.1", - "phpunit/php-text-template": ">=1.1.1", - "phpunit/php-code-coverage": ">=1.2.1", - "phpunit/php-timer": ">=1.0.2", - "phpunit/phpunit-mock-objects": ">=1.2.0,<1.3.0", - "symfony/yaml": ">=2.1.0,<2.2.0", - "ext-dom": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*" - }, - "suggest": { - "phpunit/php-invoker": ">=1.1.0", - "ext-json": "*", - "ext-simplexml": "*", - "ext-tokenizer": "*" - }, - "time": "2013-01-09 22:41:02", - "bin": [ - "composer/bin/phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.7.x-dev" - } - }, - "autoload": { - "classmap": [ - "PHPUnit/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "", - "../../symfony/yaml/" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "http://www.phpunit.de/", - "keywords": [ - "testing", - "phpunit", - "xunit" - ] - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "1.2.2", - "source": { - "type": "git", - "url": "git://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "1.2.2" - }, - "dist": { - "type": "zip", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects/archive/1.2.2.zip", - "reference": "1.2.2", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "phpunit/php-text-template": ">=1.1.1@stable" - }, - "suggest": { - "ext-soap": "*" - }, - "time": "2012-11-05 10:39:13", - "type": "library", - "autoload": { - "classmap": [ - "PHPUnit/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ] - }, - { - "name": "symfony/yaml", - "version": "v2.1.6", - "target-dir": "Symfony/Component/Yaml", - "source": { - "type": "git", - "url": "https://github.com/symfony/Yaml", - "reference": "v2.1.6" - }, - "dist": { - "type": "zip", - "url": "https://github.com/symfony/Yaml/archive/v2.1.6.zip", - "reference": "v2.1.6", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "time": "2012-12-06 10:00:55", - "type": "library", - "autoload": { - "psr-0": { - "Symfony\\Component\\Yaml": "" - } - }, - "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" + "name": "Colin Mollenhour", + "email": "colin@mollenhour.com" } ], - "description": "Symfony Yaml Component", - "homepage": "http://symfony.com/" + "description": "Credis is a lightweight interface to the Redis key-value store which wraps the phpredis library when available for better performance.", + "homepage": "https://github.com/colinmollenhour/credis", + "support": { + "source": "https://github.com/chrisboulton/credis/tree/master" + } } ], + "packages-dev": null, "aliases": [ ], "minimum-stability": "stable", - "stability-flags": [ - - ] + "stability-flags": { + "colinmollenhour/credis": 20 + } } diff --git a/lib/Redisent/LICENSE b/lib/Redisent/LICENSE deleted file mode 100644 index 385910fb..00000000 --- a/lib/Redisent/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2009 Justin Poliey - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/lib/Redisent/README.markdown b/lib/Redisent/README.markdown deleted file mode 100644 index 3edb8438..00000000 --- a/lib/Redisent/README.markdown +++ /dev/null @@ -1,67 +0,0 @@ -# Redisent - -Redisent is a simple, no-nonsense interface to the [Redis](http://code.google.com/p/redis/) key-value store for modest developers. -Due to the way it is implemented, it is flexible and tolerant of changes to the Redis protocol. - -## Getting to work - -If you're at all familiar with the Redis protocol and PHP objects, you've already mastered Redisent. -All Redisent does is map the Redis protocol to a PHP object, abstract away the nitty-gritty, and make the return values PHP compatible. - - require 'redisent.php'; - $redis = new Redisent('localhost'); - $redis->set('awesome', 'absolutely'); - echo sprintf('Is Redisent awesome? %s.\n', $redis->get('awesome')); - -You use the exact same command names, and the exact same argument order. **How wonderful.** How about a more complex example? - - require 'redisent.php'; - $redis = new Redisent('localhost'); - $redis->rpush('particles', 'proton'); - $redis->rpush('particles', 'electron'); - $redis->rpush('particles', 'neutron'); - $particles = $redis->lrange('particles', 0, -1); - $particle_count = $redis->llen('particles'); - echo "

The {$particle_count} particles that make up atoms are:

"; - echo "
    "; - foreach ($particles as $particle) { - echo "
  • {$particle}
  • "; - } - echo "
"; - -Be aware that Redis error responses will be wrapped in a RedisException class and thrown, so do be sure to use proper coding techniques. - -## Clustering your servers - -Redisent also includes a way for developers to fully utilize the scalability of Redis with multiple servers and [consistent hashing](http://en.wikipedia.org/wiki/Consistent_hashing). -Using the RedisentCluster class, you can use Redisent the same way, except that keys will be hashed across multiple servers. -Here is how to set up a cluster: - - include 'redisent_cluster.php'; - - $cluster = new RedisentCluster(array( - array('host' => '127.0.0.1', 'port' => 6379), - array('host' => '127.0.0.1', 'port' => 6380) - )); - -You can then use Redisent the way you normally would, i.e., `$cluster->set('key', 'value')` or `$cluster->lrange('particles', 0, -1)`. -But what about when you need to use commands that are server specific and do not operate on keys? You can use routing, with the `RedisentCluster::to` method. -To use routing, you need to assign a server an alias in the constructor of the Redis cluster. Aliases are not required on all servers, just the ones you want to be able to access directly. - - include 'redisent_cluster.php'; - - $cluster = new RedisentCluster(array( - 'alpha' => array('host' => '127.0.0.1', 'port' => 6379), - array('host' => '127.0.0.1', 'port' => 6380) - )); - -Now there is an alias of the server running on 127.0.0.1:6379 called **alpha**, and can be interacted with like this: - - // get server info - $cluster->to('alpha')->info(); - -Now you have complete programatic control over your Redis servers. - -## About - -© 2009 [Justin Poliey](http://justinpoliey.com) \ No newline at end of file diff --git a/lib/Redisent/Redisent.php b/lib/Redisent/Redisent.php deleted file mode 100644 index 92ccd026..00000000 --- a/lib/Redisent/Redisent.php +++ /dev/null @@ -1,165 +0,0 @@ - - * @copyright 2009 Justin Poliey - * @license http://www.opensource.org/licenses/mit-license.php The MIT License - * @package Redisent - */ - -define('CRLF', sprintf('%s%s', chr(13), chr(10))); - -/** - * Wraps native Redis errors in friendlier PHP exceptions - * Only declared if class doesn't already exist to ensure compatibility with php-redis - */ -if (! class_exists('RedisException', false)) { - class RedisException extends Exception { - } -} - -/** - * Redisent, a Redis interface for the modest among us - */ -class Redisent { - - /** - * Socket connection to the Redis server - * @var resource - * @access private - */ - private $__sock; - - /** - * Host of the Redis server - * @var string - * @access public - */ - public $host; - - /** - * Port on which the Redis server is running - * @var integer - * @access public - */ - public $port; - - /** - * Number of times to attempt a reconnect - * - * @var int - */ - public $max_reconnects = 3; - - /** - * Creates a Redisent connection to the Redis server on host {@link $host} and port {@link $port}. - * @param string $host The hostname of the Redis server - * @param integer $port The port number of the Redis server - */ - function __construct($host, $port = 6379) { - $this->host = $host; - $this->port = $port; - $this->establishConnection(); - } - - function establishConnection() { - $this->__sock = fsockopen($this->host, $this->port, $errno, $errstr); - if (!$this->__sock) { - throw new Exception("{$errno} - {$errstr}"); - } - } - - function __destruct() { - fclose($this->__sock); - } - - function __call($name, $args) { - - /* Build the Redis unified protocol command */ - array_unshift($args, strtoupper($name)); - $command = sprintf('*%d%s%s%s', count($args), CRLF, implode(array_map(array($this, 'formatArgument'), $args), CRLF), CRLF); - - /* Open a Redis connection and execute the command */ - $reconnects = 0; - for ($written = 0; $written < strlen($command); $written += $fwrite) { - $fwrite = @fwrite($this->__sock, substr($command, $written)); - if ($fwrite === FALSE || $fwrite === 0) { - if ($reconnects >= (int)$this->max_reconnects) { - throw new Exception('Failed to write entire command to stream'); - }else{ - fclose($this->__sock); - sleep(1); - $this->establishConnection(); - $reconnects++; - } - } - } - - /* Parse the response based on the reply identifier */ - $reply = trim(fgets($this->__sock, 512)); - switch (substr($reply, 0, 1)) { - /* Error reply */ - case '-': - throw new RedisException(substr(trim($reply), 4)); - break; - /* Inline reply */ - case '+': - $response = substr(trim($reply), 1); - break; - /* Bulk reply */ - case '$': - $response = null; - if ($reply == '$-1') { - break; - } - $read = 0; - $size = substr($reply, 1); - do { - $block_size = ($size - $read) > 1024 ? 1024 : ($size - $read); - $response .= fread($this->__sock, $block_size); - $read += $block_size; - } while ($read < $size); - fread($this->__sock, 2); /* discard crlf */ - break; - /* Multi-bulk reply */ - case '*': - $count = substr($reply, 1); - if ($count == '-1') { - return null; - } - $response = array(); - for ($i = 0; $i < $count; $i++) { - $bulk_head = trim(fgets($this->__sock, 512)); - $size = substr($bulk_head, 1); - if ($size == '-1') { - $response[] = null; - } - else { - $read = 0; - $block = ""; - do { - $block_size = ($size - $read) > 1024 ? 1024 : ($size - $read); - $block .= fread($this->__sock, $block_size); - $read += $block_size; - } while ($read < $size); - fread($this->__sock, 2); /* discard crlf */ - $response[] = $block; - } - } - break; - /* Integer reply */ - case ':': - $response = intval(substr(trim($reply), 1)); - break; - default: - throw new RedisException("invalid server response: {$reply}"); - break; - } - /* Party on */ - return $response; - } - - private function formatArgument($arg) { - return sprintf('$%d%s%s', strlen($arg), CRLF, $arg); - } -} \ No newline at end of file diff --git a/lib/Redisent/RedisentCluster.php b/lib/Redisent/RedisentCluster.php deleted file mode 100644 index 215726ee..00000000 --- a/lib/Redisent/RedisentCluster.php +++ /dev/null @@ -1,138 +0,0 @@ - - * @copyright 2009 Justin Poliey - * @license http://www.opensource.org/licenses/mit-license.php The MIT License - * @package Redisent - */ - -require_once __DIR__ . '/Redisent.php'; - -/** - * A generalized Redisent interface for a cluster of Redis servers - */ -class RedisentCluster { - - /** - * Collection of Redisent objects attached to Redis servers - * @var array - * @access private - */ - private $redisents; - - /** - * Aliases of Redisent objects attached to Redis servers, used to route commands to specific servers - * @see RedisentCluster::to - * @var array - * @access private - */ - private $aliases; - - /** - * Hash ring of Redis server nodes - * @var array - * @access private - */ - private $ring; - - /** - * Individual nodes of pointers to Redis servers on the hash ring - * @var array - * @access private - */ - private $nodes; - - /** - * Number of replicas of each node to make around the hash ring - * @var integer - * @access private - */ - private $replicas = 128; - - /** - * The commands that are not subject to hashing - * @var array - * @access private - */ - private $dont_hash = array( - 'RANDOMKEY', 'DBSIZE', - 'SELECT', 'MOVE', 'FLUSHDB', 'FLUSHALL', - 'SAVE', 'BGSAVE', 'LASTSAVE', 'SHUTDOWN', - 'INFO', 'MONITOR', 'SLAVEOF' - ); - - /** - * Creates a Redisent interface to a cluster of Redis servers - * @param array $servers The Redis servers in the cluster. Each server should be in the format array('host' => hostname, 'port' => port) - */ - function __construct($servers) { - $this->ring = array(); - $this->aliases = array(); - foreach ($servers as $alias => $server) { - $this->redisents[] = new Redisent($server['host'], $server['port']); - if (is_string($alias)) { - $this->aliases[$alias] = $this->redisents[count($this->redisents)-1]; - } - for ($replica = 1; $replica <= $this->replicas; $replica++) { - $this->ring[crc32($server['host'].':'.$server['port'].'-'.$replica)] = $this->redisents[count($this->redisents)-1]; - } - } - ksort($this->ring, SORT_NUMERIC); - $this->nodes = array_keys($this->ring); - } - - /** - * Routes a command to a specific Redis server aliased by {$alias}. - * @param string $alias The alias of the Redis server - * @return Redisent The Redisent object attached to the Redis server - */ - function to($alias) { - if (isset($this->aliases[$alias])) { - return $this->aliases[$alias]; - } - else { - throw new Exception("That Redisent alias does not exist"); - } - } - - /* Execute a Redis command on the cluster */ - function __call($name, $args) { - - /* Pick a server node to send the command to */ - $name = strtoupper($name); - if (!in_array($name, $this->dont_hash)) { - $node = $this->nextNode(crc32($args[0])); - $redisent = $this->ring[$node]; - } - else { - $redisent = $this->redisents[0]; - } - - /* Execute the command on the server */ - return call_user_func_array(array($redisent, $name), $args); - } - - /** - * Routes to the proper server node - * @param integer $needle The hash value of the Redis command - * @return Redisent The Redisent object associated with the hash - */ - private function nextNode($needle) { - $haystack = $this->nodes; - while (count($haystack) > 2) { - $try = floor(count($haystack) / 2); - if ($haystack[$try] == $needle) { - return $needle; - } - if ($needle < $haystack[$try]) { - $haystack = array_slice($haystack, 0, $try + 1); - } - if ($needle > $haystack[$try]) { - $haystack = array_slice($haystack, $try + 1); - } - } - return $haystack[count($haystack)-1]; - } - -} \ No newline at end of file diff --git a/lib/Resque.php b/lib/Resque.php index c3254a36..88cec4cb 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -71,21 +71,7 @@ public static function redis() $server = 'localhost:6379'; } - if(is_array($server)) { - self::$redis = new Resque_RedisCluster($server); - } - else { - if (strpos($server, 'unix:') === false) { - list($host, $port) = explode(':', $server); - } - else { - $host = $server; - $port = null; - } - self::$redis = new Resque_Redis($host, $port); - } - - self::$redis->select(self::$redisDatabase); + self::$redis = new Resque_Redis($server, self::$redisDatabase); return self::$redis; } diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 1cff624c..f6f6dc66 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -1,25 +1,22 @@ * @license http://www.opensource.org/licenses/mit-license.php */ -class Resque_Redis extends Redisent +class Resque_Redis { /** * Redis namespace * @var string */ private static $defaultNamespace = 'resque:'; + + private $server; + private $database; + /** * @var array List of all commands in Redis that supply a key as their * first argument. Used to prefix keys with the Resque namespace. @@ -81,7 +78,7 @@ class Resque_Redis extends Redisent // msetnx // mset // renamenx - + /** * Set Redis namespace (prefix) default: resque * @param string $namespace @@ -93,7 +90,36 @@ public static function prefix($namespace) } self::$defaultNamespace = $namespace; } - + + public function __construct($server, $database = null) + { + $this->server = $server; + $this->database = $database; + + if (is_array($this->server)) { + $this->driver = new Credis_Cluster($server); + } + else { + $port = null; + $host = $server; + + // If not a UNIX socket path or tcp:// formatted connections string + // assume host:port combination. + if (strpos($server, '/') === false) { + $parts = explode(':', $server); + if (isset($parts[1])) { + $port = $parts[1]; + } + $host = $parts[0]; + } + $this->driver = new Credis_Client($host, $port); + } + + if ($this->database !== null) { + $this->driver->select($database); + } + } + /** * Magic method to handle all function requests and prefix key based * operations with the {self::$defaultNamespace} key prefix. @@ -103,14 +129,13 @@ public static function prefix($namespace) * @return mixed Return value from Resident::call() based on the command. */ public function __call($name, $args) { - $args = func_get_args(); if(in_array($name, $this->keyCommands)) { - $args[1][0] = self::$defaultNamespace . $args[1][0]; + $args[0] = self::$defaultNamespace . $args[0]; } try { - return parent::__call($name, $args[1]); + return $this->driver->__call($name, $args); } - catch(RedisException $e) { + catch(CredisException $e) { return false; } } @@ -130,4 +155,4 @@ public static function removePrefix($string) return $string; } } -?> +?> \ No newline at end of file diff --git a/lib/Resque/RedisCluster.php b/lib/Resque/RedisCluster.php deleted file mode 100644 index 21caeb77..00000000 --- a/lib/Resque/RedisCluster.php +++ /dev/null @@ -1,117 +0,0 @@ - - * @license http://www.opensource.org/licenses/mit-license.php - */ -class Resque_RedisCluster extends RedisentCluster -{ - /** - * Redis namespace - * @var string - */ - private static $defaultNamespace = 'resque:'; - /** - * @var array List of all commands in Redis that supply a key as their - * first argument. Used to prefix keys with the Resque namespace. - */ - private $keyCommands = array( - 'exists', - 'del', - 'type', - 'keys', - 'expire', - 'ttl', - 'move', - 'set', - 'get', - 'getset', - 'setnx', - 'incr', - 'incrby', - 'decrby', - 'decrby', - 'rpush', - 'lpush', - 'llen', - 'lrange', - 'ltrim', - 'lindex', - 'lset', - 'lrem', - 'lpop', - 'rpop', - 'sadd', - 'srem', - 'spop', - 'scard', - 'sismember', - 'smembers', - 'srandmember', - 'zadd', - 'zrem', - 'zrange', - 'zrevrange', - 'zrangebyscore', - 'zcard', - 'zscore', - 'zremrangebyscore', - 'sort' - ); - // sinterstore - // sunion - // sunionstore - // sdiff - // sdiffstore - // sinter - // smove - // rename - // rpoplpush - // mget - // msetnx - // mset - // renamenx - - /** - * Set Redis namespace (prefix) default: resque - * @param string $namespace - */ - public static function prefix($namespace) - { - if (strpos($namespace, ':') === false) { - $namespace .= ':'; - } - self::$defaultNamespace = $namespace; - } - - /** - * Magic method to handle all function requests and prefix key based - * operations with the '{self::$defaultNamespace}' key prefix. - * - * @param string $name The name of the method called. - * @param array $args Array of supplied arguments to the method. - * @return mixed Return value from Resident::call() based on the command. - */ - public function __call($name, $args) { - $args = func_get_args(); - if(in_array($name, $this->keyCommands)) { - $args[1][0] = self::$defaultNamespace . $args[1][0]; - } - try { - return parent::__call($name, $args[1]); - } - catch(RedisException $e) { - return false; - } - } -} -?> diff --git a/test/Resque/Tests/TestCase.php b/test/Resque/Tests/TestCase.php index 6c052d3c..4ed65dee 100644 --- a/test/Resque/Tests/TestCase.php +++ b/test/Resque/Tests/TestCase.php @@ -15,7 +15,7 @@ public function setUp() { $config = file_get_contents(REDIS_CONF); preg_match('#^\s*port\s+([0-9]+)#m', $config, $matches); - $this->redis = new Redisent('localhost', $matches[1]); + $this->redis = new Credis_Client('localhost', $matches[1]); // Flush redis $this->redis->flushAll(); From b0900d63902c30d370e3e8e211ece9131ca79378 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 12 Jan 2013 23:56:16 +1100 Subject: [PATCH 072/194] add package suggestions (proctitle and redis extensions) --- composer.json | 4 ++++ composer.lock | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9b67eaec..32f92ad9 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,10 @@ "php": ">=5.3.0", "colinmollenhour/credis": "dev-master" }, + "suggest": { + "ext-proctitle": "Allows php-resque to rename the title of UNIX processes to show the status of a worker.", + "ext-redis": "Native PHP extension for Redis connectivity. Credis will automatically utilize when available." + }, "require-dev": { "phpunit/phpunit": "3.7.*" }, diff --git a/composer.lock b/composer.lock index 472226fd..877c2434 100644 --- a/composer.lock +++ b/composer.lock @@ -1,5 +1,5 @@ { - "hash": "af626b3a277bd0ab503c2c107327a88e", + "hash": "d37909ad0ffc11ed4d1e67dcaabe00b2", "packages": [ { "name": "colinmollenhour/credis", From ac28ca36d5e1e83361383aee215b912cbd0e3d33 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sun, 13 Jan 2013 01:06:32 +1100 Subject: [PATCH 073/194] test with and without phpredis extension --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index b1b8e8c8..c78e442f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,5 +2,9 @@ language: php php: - 5.3 - 5.4 +env: + - REDIS_STANDALONE=0 + - REDIS_STANDALONE=1 before_script: + - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then pecl install redis && echo \"extension=redis.so\" >> `php --ini | grep \"Loaded Configuration\" | sed -e \"s|.*:\s*||\"`; fi" - composer install --dev \ No newline at end of file From ab9195cf19b1c4f5a9633589828e31231f6951f4 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sun, 13 Jan 2013 01:15:04 +1100 Subject: [PATCH 074/194] php-redis is not available via pecl, install using wget (not nice) --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index c78e442f..e24a56f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,5 +6,7 @@ env: - REDIS_STANDALONE=0 - REDIS_STANDALONE=1 before_script: + - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then wget https://github.com/nicolasff/phpredis/archive/2.2.2.zip -O php-redis.zip && unzip php-redis.zip; fi" + - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then cd phpredis-2.2.2/ && phpize && ./configure && make && make install; fi" - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then pecl install redis && echo \"extension=redis.so\" >> `php --ini | grep \"Loaded Configuration\" | sed -e \"s|.*:\s*||\"`; fi" - composer install --dev \ No newline at end of file From f082ec872e317226622372bbbefd55b18e1e72b5 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sun, 13 Jan 2013 01:16:19 +1100 Subject: [PATCH 075/194] remove pecl install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e24a56f9..7e6faf6d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,5 +8,5 @@ env: before_script: - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then wget https://github.com/nicolasff/phpredis/archive/2.2.2.zip -O php-redis.zip && unzip php-redis.zip; fi" - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then cd phpredis-2.2.2/ && phpize && ./configure && make && make install; fi" - - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then pecl install redis && echo \"extension=redis.so\" >> `php --ini | grep \"Loaded Configuration\" | sed -e \"s|.*:\s*||\"`; fi" + - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then echo \"extension=redis.so\" >> `php --ini | grep \"Loaded Configuration\" | sed -e \"s|.*:\s*||\"`; fi" - composer install --dev \ No newline at end of file From 6800fbe5ac8000c617f53c94a3621b74908f52e7 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sun, 13 Jan 2013 02:59:06 +1100 Subject: [PATCH 076/194] fix compatibility with phpredis * implement a fork helper method that closes the connection to redis before forking (instead of resetting after) to work around bugs with phpredis/socket fork handling * phpredis does not automatically typecast to string, so worker name must be typecasted when registering --- bin/resque | 2 +- lib/Resque.php | 43 ++++++++++++++++++++++++++++--------------- lib/Resque/Worker.php | 25 ++----------------------- 3 files changed, 31 insertions(+), 39 deletions(-) diff --git a/bin/resque b/bin/resque index 687f6c40..186e1eef 100644 --- a/bin/resque +++ b/bin/resque @@ -68,7 +68,7 @@ if(!empty($COUNT) && $COUNT > 1) { if($count > 1) { for($i = 0; $i < $count; ++$i) { - $pid = pcntl_fork(); + $pid = Resque::fork(); if($pid == -1) { die("Could not fork worker ".$i."\n"); } diff --git a/lib/Resque.php b/lib/Resque.php index 88cec4cb..fa22ed1f 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -26,12 +26,6 @@ class Resque */ protected static $redisDatabase = 0; - /** - * @var int PID of current process. Used to detect changes when forking - * and implement "thread" safety to avoid race conditions. - */ - protected static $pid = null; - /** * Given a host/port combination separated by a colon, set it as * the redis server that Resque will talk to. @@ -54,15 +48,7 @@ public static function setBackend($server, $database = 0) */ public static function redis() { - // Detect when the PID of the current process has changed (from a fork, etc) - // and force a reconnect to redis. - $pid = getmypid(); - if (self::$pid !== $pid) { - self::$redis = null; - self::$pid = $pid; - } - - if(!is_null(self::$redis)) { + if (self::$redis !== null) { return self::$redis; } @@ -75,6 +61,33 @@ public static function redis() return self::$redis; } + /** + * fork() helper method for php-resque that handles issues PHP socket + * and phpredis have with passing around sockets between child/parent + * processes. + * + * Will close connection to Redis before forking. + * + * @return int Return vars as per pcntl_fork() + */ + public static function fork() + { + if(!function_exists('pcntl_fork')) { + return -1; + } + + // Close the connection to Redis before forking. + // This is a workaround for issues phpredis has. + self::$redis = null; + + $pid = pcntl_fork(); + if($pid === -1) { + throw new RuntimeException('Unable to fork child worker.'); + } + + return $pid; + } + /** * Push a job to the end of a specific queue. If the queue does not * exist, then create it as well. diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index d103810a..5dc678df 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -184,7 +184,7 @@ public function work($interval = 5) Resque_Event::trigger('beforeFork', $job); $this->workingOn($job); - $this->child = $this->fork(); + $this->child = Resque::fork(); // Forked and we're the child. Run the job. if ($this->child === 0 || $this->child === false) { @@ -286,27 +286,6 @@ public function queues($fetch = true) return $queues; } - /** - * Attempt to fork a child process from the parent to run a job in. - * - * Return values are those of pcntl_fork(). - * - * @return int -1 if the fork failed, 0 for the forked child, the PID of the child for the parent. - */ - private function fork() - { - if(!function_exists('pcntl_fork')) { - return false; - } - - $pid = pcntl_fork(); - if($pid === -1) { - throw new RuntimeException('Unable to fork child worker.'); - } - - return $pid; - } - /** * Perform necessary actions to start a worker. */ @@ -474,7 +453,7 @@ public function workerPids() */ public function registerWorker() { - Resque::redis()->sadd('workers', $this); + Resque::redis()->sadd('workers', (string)$this); Resque::redis()->set('worker:' . (string)$this . ':started', strftime('%a %b %d %H:%M:%S %Z %Y')); } From aae168392c928b276706374936530bf424d9869d Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sun, 13 Jan 2013 03:02:53 +1100 Subject: [PATCH 077/194] just use built in phpunit on travis ci --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7e6faf6d..cdb44788 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,4 +9,4 @@ before_script: - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then wget https://github.com/nicolasff/phpredis/archive/2.2.2.zip -O php-redis.zip && unzip php-redis.zip; fi" - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then cd phpredis-2.2.2/ && phpize && ./configure && make && make install; fi" - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then echo \"extension=redis.so\" >> `php --ini | grep \"Loaded Configuration\" | sed -e \"s|.*:\s*||\"`; fi" - - composer install --dev \ No newline at end of file + - composer install \ No newline at end of file From 762daf9f368ac4820d116d71a27687c692431e66 Mon Sep 17 00:00:00 2001 From: Jesse O'Brien Date: Mon, 21 Jan 2013 15:50:24 -0500 Subject: [PATCH 078/194] Extra check for vendor 3 folders up. Failure to check up *3* folders when running the binary from chrisboulton/php-resque/bin/ results in never finding the autoload file when it tries to load up the composer dependencies. --- bin/resque | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/resque b/bin/resque index 186e1eef..40c55891 100644 --- a/bin/resque +++ b/bin/resque @@ -4,6 +4,7 @@ // Find and initialize Composer $files = array( __DIR__ . '/../../vendor/autoload.php', + __DIR__ . '/../../../autoload.php', __DIR__ . '/../../../../autoload.php', __DIR__ . '/../vendor/autoload.php', ); From afd84de15577becf5b7636d54cc460a09188335d Mon Sep 17 00:00:00 2001 From: Carlos Viglietta Date: Wed, 6 Feb 2013 12:37:12 -0200 Subject: [PATCH 079/194] REDIS_BACKEND_DB env variable added It's enable the possibility of use a different db index on redis backend --- bin/resque | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bin/resque b/bin/resque index 186e1eef..be85f67d 100644 --- a/bin/resque +++ b/bin/resque @@ -30,8 +30,12 @@ if(empty($QUEUE)) { } $REDIS_BACKEND = getenv('REDIS_BACKEND'); +$REDIS_BACKEND_DB = getenv('REDIS_BACKEND_DB'); if(!empty($REDIS_BACKEND)) { - Resque::setBackend($REDIS_BACKEND); + if (empty($REDIS_BACKEND_DB)) + Resque::setBackend($REDIS_BACKEND); + else + Resque::setBackend($REDIS_BACKEND, $REDIS_BACKEND_DB); } $logLevel = 0; From 4b2bbe492b5b71a0e7d3f8d82735018b901a8b0f Mon Sep 17 00:00:00 2001 From: Lee Boynton Date: Wed, 20 Feb 2013 16:25:14 +0000 Subject: [PATCH 080/194] Fix composer example --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2b94eac9..8e119885 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ If you're not familiar with Composer, please see . { ... "require": { - "php": ">=5.3.0" + "chrisboulton/php-resque": "1.2.x" }, ... } @@ -370,4 +370,4 @@ Called after a job has been queued using the `Resque::enqueue` method. Arguments * maetl * Matt Heath * jjfrey -* scragg0x \ No newline at end of file +* scragg0x From 6a429c2f21174b5429f56871af22c07d19616291 Mon Sep 17 00:00:00 2001 From: TrimbleTodd Date: Wed, 20 Feb 2013 11:41:41 -0500 Subject: [PATCH 081/194] adding support for remote redis instances (such as redistogo) that require authentication --- lib/Resque/Redis.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index f6f6dc66..bbb0643c 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -101,6 +101,7 @@ public function __construct($server, $database = null) } else { $port = null; + $password = null; $host = $server; // If not a UNIX socket path or tcp:// formatted connections string @@ -111,8 +112,19 @@ public function __construct($server, $database = null) $port = $parts[1]; } $host = $parts[0]; + }else if (strpos($server, 'redis://') !== false){ + // Redis format is: + // redis://[user]:[password]@[host]:[port] + list($userpwd,$hostport) = explode('@', $server); + $userpwd = substr($userpwd, strpos($userpwd, 'redis://')+8); + list($host, $port) = explode(':', $hostport); + list($user, $password) = explode(':', $userpwd); } + $this->driver = new Credis_Client($host, $port); + if (isset($password)){ + $this->driver->auth($password); + } } if ($this->database !== null) { From 3b4c46e039785b4b9cf40dd477321853a1638be7 Mon Sep 17 00:00:00 2001 From: Corey Ballou Date: Thu, 21 Feb 2013 07:37:16 -0500 Subject: [PATCH 082/194] Fixed the Resque_Worker log method to properly handle NORMAL vs VERBOSE logging. --- lib/Resque/Worker.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 5dc678df..45852bb6 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -169,7 +169,7 @@ public function work($interval = 5) break; } // If no job was found, we sleep for $interval before continuing and checking again - $this->log('Sleeping for ' . $interval, true); + $this->log('Sleeping for ' . $interval, self::LOG_VERBOSE); if($this->paused) { $this->updateProcLine('Paused'); } @@ -517,16 +517,21 @@ public function __toString() /** * Output a given log message to STDOUT. * - * @param string $message Message to output. + * @param string $message Message to output. + * @param int $logLevel The logging level to capture */ - public function log($message) + public function log($message, $logLevel = self::LOG_NORMAL) { - if($this->logLevel == self::LOG_NORMAL) { - fwrite(STDOUT, "*** " . $message . "\n"); + if ($logLevel > $this->logLevel) { + return; } - else if($this->logLevel == self::LOG_VERBOSE) { - fwrite(STDOUT, "** [" . strftime('%T %Y-%m-%d') . "] " . $message . "\n"); + + if ($this->logLevel == self::LOG_NORMAL) { + fwrite(STDOUT, "*** " . $message . "\n"); + return; } + + fwrite(STDOUT, "** [" . strftime('%T %Y-%m-%d') . "] " . $message . "\n"); } /** From ff0d2bc655339fa7d2cc284e97a36cc5bf96a910 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Tue, 12 Mar 2013 09:55:03 +0100 Subject: [PATCH 083/194] Added test for blpop --- test/Resque/Tests/WorkerTest.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/Resque/Tests/WorkerTest.php b/test/Resque/Tests/WorkerTest.php index b2f0e000..b0001c9e 100644 --- a/test/Resque/Tests/WorkerTest.php +++ b/test/Resque/Tests/WorkerTest.php @@ -247,4 +247,27 @@ public function testWorkerFailsUncompletedJobsOnExit() $this->assertEquals(1, Resque_Stat::get('failed')); } + + public function testBlockingListPop() + { + $worker = new Resque_Worker('jobs'); + $worker->registerWorker(); + + Resque::enqueue('jobs', 'Test_Job_1'); + Resque::enqueue('jobs', 'Test_Job_2'); + + $i = 1; + while($job = $worker->reserve(60)) + { + $this->assertEquals('Test_Job_' . $i, $job->payload['class']); + + if($i == 2) { + break; + } + + $i++; + } + + $this->assertEquals(2, $i); + } } \ No newline at end of file From 132531e1a2a2d1e0905c353914e5b0511e1bb77b Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Tue, 12 Mar 2013 11:18:37 +0100 Subject: [PATCH 084/194] WIP --- bin/resque | 1 - demo/job.php | 5 +- demo/queue.php | 2 +- lib/Resque.php | 33 +++++++-- lib/Resque/Job.php | 49 +++++++++---- lib/Resque/Redis.php | 8 ++- lib/Resque/Worker.php | 158 ++++++++++++++++++++++-------------------- 7 files changed, 152 insertions(+), 104 deletions(-) diff --git a/bin/resque b/bin/resque index 78befad4..2cb5ffd9 100644 --- a/bin/resque +++ b/bin/resque @@ -1,4 +1,3 @@ -#!/usr/bin/env php '); + sleep(1); + fwrite(STDOUT, 'Job ended!' . PHP_EOL); } } ?> \ No newline at end of file diff --git a/demo/queue.php b/demo/queue.php index 95ff5b05..393df87e 100644 --- a/demo/queue.php +++ b/demo/queue.php @@ -14,6 +14,6 @@ ), ); -$jobId = Resque::enqueue('default', $argv[1], $args, true); +$jobId = Resque::enqueue($argv[1], $argv[2], $args, true); echo "Queued job ".$jobId."\n\n"; ?> \ No newline at end of file diff --git a/lib/Resque.php b/lib/Resque.php index bd29e846..2e459f0e 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -110,21 +110,40 @@ public static function push($queue, $item) * @param string $queue The name of the queue to fetch an item from. * @return array Decoded item from the queue. */ - public static function pop($queue, $interval = null) + public static function pop($queue) { - if($interval == null) { - $item = self::redis()->lpop('queue:' . $queue); - } else { - $item = self::redis()->blpop('queue:' . $queue, $interval ? $interval : Resque::DEFAULT_INTERVAL); - } + $item = self::redis()->lpop('queue:' . $queue); if(!$item) { return; } - return json_decode($interval == 0 ? $item : $item[1], true); + return json_decode($item, true); } + /** + * Pop an item off the end of the specified queue, decode it and + * return it. + * + * @param string $queue The name of the queue to fetch an item from. + * @return array Decoded item from the queue. + */ + public static function blpop($queues, $interval = null) + { + $list = array(); + foreach($queues AS $queue) { + $list[] = 'queue:' . $queue; + } + + $item = self::redis()->blpop($list, $interval ? (int)$interval : Resque::DEFAULT_INTERVAL); + + if(!$item) { + return; + } + + return json_decode($item[1], true); + } + /** * Return the size (number of pending jobs) of the specified queue. * diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 5066c276..0b1f01ed 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -71,22 +71,41 @@ public static function create($queue, $class, $args = null, $monitor = false) return $id; } - /** - * Find the next available job from the specified queue and return an - * instance of Resque_Job for it. - * - * @param string $queue The name of the queue to check for a job in. - * @return null|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. - */ - public static function reserve($queue, $interval = null) - { - $payload = Resque::pop($queue, $interval); - if(!is_array($payload)) { - return false; - } + /** + * Find the next available job from the specified queue and return an + * instance of Resque_Job for it. + * + * @param string $queue The name of the queue to check for a job in. + * @return null|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. + */ + public static function reserve($queue) + { + $payload = Resque::pop($queue); + if(!is_array($payload)) { + return false; + } - return new Resque_Job($queue, $payload); - } + return new Resque_Job($queue, $payload); + } + + /** + * Find the next available job from the specified queue and return an + * instance of Resque_Job for it. + * + * @param string $queue The name of the queue to check for a job in. + * @return null|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. + */ + public static function reserveBlocking($queues, $interval = null) + { + $payload = Resque::blpop($queues, $interval); + if(!is_array($payload)) { + return false; + } + + var_dump($payload); + + return new Resque_Job($payload->queue, $payload); + } /** * Update the status of the current job. diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 44471461..6cef3d2d 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -143,7 +143,13 @@ public function __construct($server, $database = null) */ public function __call($name, $args) { if(in_array($name, $this->keyCommands)) { - $args[0] = self::$defaultNamespace . $args[0]; + if(is_array($args[0])) { + foreach($args[0] AS $i => $v) { + $args[0][$i] = self::$defaultNamespace . $v; + } + } else { + $args[0] = self::$defaultNamespace . $args[0]; + } } try { return $this->driver->__call($name, $args); diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 204aae68..03487f58 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -152,70 +152,53 @@ public function work($interval = Resque::DEFAULT_INTERVAL) $this->updateProcLine('Starting'); $this->startup(); - while(true) { - if($this->shutdown) { - break; - } + while($job = $this->reserveBlocking($interval)) { + $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); - // Attempt to find and reserve a job - $job = false; - if(!$this->paused) { - $job = $this->reserve($interval); - } + $this->log('got ' . $job); + Resque_Event::trigger('beforeFork', $job); + $this->workingOn($job); - $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); + $this->child = Resque::fork(); - if(!$job) { - // For an interval of 0, break now - helps with unit testing etc - if($interval == 0) { - break; + // Forked and we're the child. Run the job. + if ($this->child === 0 || $this->child === false) { + $status = 'Processing ' . $job->queue . ' since ' . strftime('%F %T'); + $this->updateProcLine($status); + $this->log($status, self::LOG_VERBOSE); + $this->perform($job); + if ($this->child === 0) { + exit(0); } + } - // If no job was found, we sleep for $interval before continuing and checking again - if($this->paused) { - $this->updateProcLine('Paused'); - usleep($interval * 1000000); //it's paused, so don't hog redis with requests. + if($this->child > 0) { + // Parent process, sit and wait + $status = 'Forked ' . $this->child . ' at ' . strftime('%F %T'); + $this->updateProcLine($status); + $this->log($status, self::LOG_VERBOSE); + + // Wait until the child process finishes before continuing + pcntl_wait($status); + $exitStatus = pcntl_wexitstatus($status); + if($exitStatus !== 0) { + $job->fail(new Resque_Job_DirtyExitException( + 'Job exited with exit code ' . $exitStatus + )); } - - continue; } - $this->log('got ' . $job); - Resque_Event::trigger('beforeFork', $job); - $this->workingOn($job); - - $this->child = Resque::fork(); - - // Forked and we're the child. Run the job. - if ($this->child === 0 || $this->child === false) { - $status = 'Processing ' . $job->queue . ' since ' . strftime('%F %T'); - $this->updateProcLine($status); - $this->log($status, self::LOG_VERBOSE); - $this->perform($job); - if ($this->child === 0) { - exit(0); - } - } - - if($this->child > 0) { - // Parent process, sit and wait - $status = 'Forked ' . $this->child . ' at ' . strftime('%F %T'); - $this->updateProcLine($status); - $this->log($status, self::LOG_VERBOSE); - - // Wait until the child process finishes before continuing - pcntl_wait($status); - $exitStatus = pcntl_wexitstatus($status); - if($exitStatus !== 0) { - $job->fail(new Resque_Job_DirtyExitException( - 'Job exited with exit code ' . $exitStatus - )); - } - } + $this->child = null; + $this->doneWorking(); - $this->child = null; - $this->doneWorking(); - } + if($this->shutdown) { + break; + } + + if($this->paused) { + break; + } + } $this->unregisterWorker(); } @@ -241,28 +224,49 @@ public function perform(Resque_Job $job) $this->log('done ' . $job); } - /** - * Attempt to find a job from the top of one of the queues for this worker. - * - * @return object|boolean Instance of Resque_Job if a job is found, false if not. - */ - public function reserve($interval = null) - { - $queues = $this->queues(); - if(!is_array($queues)) { - return; - } - foreach($queues as $queue) { - $this->log('Checking ' . $queue . ' with interval ' . $interval, self::LOG_VERBOSE); - $job = Resque_Job::reserve($queue, $interval); - if($job) { - $this->log('Found job on ' . $queue, self::LOG_VERBOSE); - return $job; - } - } - - return false; - } + /** + * Attempt to find a job from the top of one of the queues for this worker. + * + * @return object|boolean Instance of Resque_Job if a job is found, false if not. + */ + public function reserve() + { + $queues = $this->queues(); + if(!is_array($queues)) { + return; + } + foreach($queues as $queue) { + $this->log('Checking ' . $queue, self::LOG_VERBOSE); + $job = Resque_Job::reserve($queue); + if($job) { + $this->log('Found job on ' . $queue, self::LOG_VERBOSE); + return $job; + } + } + + return false; + } + + /** + * Attempt to find a job from the top of one of the queues for this worker. + * + * @return object|boolean Instance of Resque_Job if a job is found, false if not. + */ + public function reserveBlocking($interval = null) + { + $queues = $this->queues(); + if(!is_array($queues)) { + return; + } + + $job = Resque_Job::reserveBlocking($queues, $interval); + if($job) { + $this->log('Found job on ' . $job->queue, self::LOG_VERBOSE); + return $job; + } + + return false; + } /** * Return an array containing all of the queues that this worker should use From c2c4d06f7b72a3d8c68c61ef443fbb0b00e87200 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Wed, 13 Mar 2013 12:41:32 +0100 Subject: [PATCH 085/194] Working blocking list pop :) --- bin/resque | 106 +------ bin/resque.php | 105 +++++++ composer.lock | 416 +++++++++++++++++++++++++++- demo/bad_job.php | 3 +- demo/check_status.php | 3 +- demo/job.php | 3 +- demo/long_job.php | 3 +- demo/php_error_job.php | 3 +- demo/queue.php | 3 +- demo/resque.php | 3 +- lib/Resque.php | 17 +- lib/Resque/Job.php | 13 +- lib/Resque/Worker.php | 99 ++++--- test/Resque/Tests/JobStatusTest.php | 6 + 14 files changed, 606 insertions(+), 177 deletions(-) mode change 100644 => 100755 bin/resque create mode 100644 bin/resque.php diff --git a/bin/resque b/bin/resque old mode 100644 new mode 100755 index 2cb5ffd9..5475c987 --- a/bin/resque +++ b/bin/resque @@ -1,105 +1,3 @@ +#!/usr/bin/env php 1) { - $count = $COUNT; -} - -if($count > 1) { - for($i = 0; $i < $count; ++$i) { - $pid = Resque::fork(); - if($pid == -1) { - die("Could not fork worker ".$i."\n"); - } - // Child, start the worker - else if(!$pid) { - $queues = explode(',', $QUEUE); - $worker = new Resque_Worker($queues); - $worker->logLevel = $logLevel; - fwrite(STDOUT, '*** Starting worker '.$worker."\n"); - $worker->work($interval); - break; - } - } -} -// Start a single worker -else { - $queues = explode(',', $QUEUE); - $worker = new Resque_Worker($queues); - $worker->logLevel = $logLevel; - - $PIDFILE = getenv('PIDFILE'); - if ($PIDFILE) { - file_put_contents($PIDFILE, getmypid()) or - die('Could not write PID information to ' . $PIDFILE); - } - - fwrite(STDOUT, '*** Starting worker '.$worker."\n"); - $worker->work($interval); -} -?> +include("resque.php"); \ No newline at end of file diff --git a/bin/resque.php b/bin/resque.php new file mode 100644 index 00000000..3fc788f5 --- /dev/null +++ b/bin/resque.php @@ -0,0 +1,105 @@ + 1) { + $count = $COUNT; +} + +if($count > 1) { + for($i = 0; $i < $count; ++$i) { + $pid = Resque::fork(); + if($pid == -1) { + die("Could not fork worker ".$i."\n"); + } + // Child, start the worker + else if(!$pid) { + $queues = explode(',', $QUEUE); + $worker = new Resque_Worker($queues); + $worker->logLevel = $logLevel; + fwrite(STDOUT, '*** Starting worker '.$worker."\n"); + $worker->work($interval, $BLOCKING); + break; + } + } +} +// Start a single worker +else { + $queues = explode(',', $QUEUE); + $worker = new Resque_Worker($queues); + $worker->logLevel = $logLevel; + + $PIDFILE = getenv('PIDFILE'); + if ($PIDFILE) { + file_put_contents($PIDFILE, getmypid()) or + die('Could not write PID information to ' . $PIDFILE); + } + + fwrite(STDOUT, '*** Starting worker '.$worker."\n"); + $worker->work($interval, $BLOCKING); +} \ No newline at end of file diff --git a/composer.lock b/composer.lock index 877c2434..760d4cf5 100644 --- a/composer.lock +++ b/composer.lock @@ -18,7 +18,6 @@ "require": { "php": ">=5.3.0" }, - "time": "2013-01-12 10:15:31", "type": "library", "autoload": { "classmap": [ @@ -39,15 +38,424 @@ "homepage": "https://github.com/colinmollenhour/credis", "support": { "source": "https://github.com/chrisboulton/credis/tree/master" - } + }, + "time": "2013-01-12 10:15:31" + } + ], + "packages-dev": [ + { + "name": "phpunit/php-code-coverage", + "version": "1.2.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "1.2.9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.9", + "reference": "1.2.9", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": ">=1.3.0@stable", + "phpunit/php-text-template": ">=1.1.1@stable", + "phpunit/php-token-stream": ">=1.1.3@stable" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.0.5" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2013-02-26 18:55:56" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.3.3", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "1.3.3" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-file-iterator/zipball/1.3.3", + "reference": "1.3.3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "File/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2012-10-11 04:44:38" + }, + { + "name": "phpunit/php-text-template", + "version": "1.1.4", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-text-template.git", + "reference": "1.1.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-text-template/zipball/1.1.4", + "reference": "1.1.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "Text/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2012-10-31 11:15:28" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.4", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-timer.git", + "reference": "1.0.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-timer/zipball/1.0.4", + "reference": "1.0.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "timer" + ], + "time": "2012-10-11 04:45:58" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.1.5", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-token-stream.git", + "reference": "1.1.5" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-token-stream/zipball/1.1.5", + "reference": "1.1.5", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "tokenizer" + ], + "time": "2012-10-11 04:47:14" + }, + { + "name": "phpunit/phpunit", + "version": "3.7.18", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "3.7.18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.18", + "reference": "3.7.18", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpunit/php-code-coverage": ">=1.2.1,<1.3.0", + "phpunit/php-file-iterator": ">=1.3.1", + "phpunit/php-text-template": ">=1.1.1", + "phpunit/php-timer": ">=1.0.2,<1.1.0", + "phpunit/phpunit-mock-objects": ">=1.2.0,<1.3.0", + "symfony/yaml": ">=2.2.0" + }, + "require-dev": { + "pear-pear/pear": "1.9.4" + }, + "suggest": { + "ext-json": "*", + "ext-simplexml": "*", + "ext-tokenizer": "*", + "phpunit/php-invoker": ">=1.1.0,<1.2.0" + }, + "bin": [ + "composer/bin/phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "", + "../../symfony/yaml/" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2013-03-07 21:45:39" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "1.2.3", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "1.2.3" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects/archive/1.2.3.zip", + "reference": "1.2.3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-text-template": ">=1.1.1@stable" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2013-01-13 10:24:48" + }, + { + "name": "symfony/yaml", + "version": "v2.2.0", + "target-dir": "Symfony/Component/Yaml", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "v2.2.0-RC3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.2.0-RC3", + "reference": "v2.2.0-RC3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "http://symfony.com/", + "time": "2013-01-27 16:49:19" } ], - "packages-dev": null, "aliases": [ ], "minimum-stability": "stable", "stability-flags": { "colinmollenhour/credis": 20 - } + }, + "platform": { + "php": ">=5.3.0" + }, + "platform-dev": [ + + ] } diff --git a/demo/bad_job.php b/demo/bad_job.php index bc126209..cd719cc2 100644 --- a/demo/bad_job.php +++ b/demo/bad_job.php @@ -5,5 +5,4 @@ public function perform() { throw new Exception('Unable to run this job!'); } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/demo/check_status.php b/demo/check_status.php index 061a83a9..645bf6d9 100644 --- a/demo/check_status.php +++ b/demo/check_status.php @@ -17,5 +17,4 @@ while(true) { fwrite(STDOUT, "Status of ".$argv[1]." is: ".$status->get()."\n"); sleep(1); -} -?> +} \ No newline at end of file diff --git a/demo/job.php b/demo/job.php index ec3d143e..ddda8932 100644 --- a/demo/job.php +++ b/demo/job.php @@ -7,5 +7,4 @@ public function perform() sleep(1); fwrite(STDOUT, 'Job ended!' . PHP_EOL); } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/demo/long_job.php b/demo/long_job.php index 8c9f0f94..1cfe5cb0 100644 --- a/demo/long_job.php +++ b/demo/long_job.php @@ -5,5 +5,4 @@ public function perform() { sleep(600); } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/demo/php_error_job.php b/demo/php_error_job.php index 93bf2bca..98244059 100644 --- a/demo/php_error_job.php +++ b/demo/php_error_job.php @@ -5,5 +5,4 @@ public function perform() { callToUndefinedFunction(); } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/demo/queue.php b/demo/queue.php index 393df87e..52f2f0ba 100644 --- a/demo/queue.php +++ b/demo/queue.php @@ -15,5 +15,4 @@ ); $jobId = Resque::enqueue($argv[1], $argv[2], $args, true); -echo "Queued job ".$jobId."\n\n"; -?> \ No newline at end of file +echo "Queued job ".$jobId."\n\n"; \ No newline at end of file diff --git a/demo/resque.php b/demo/resque.php index cdaf7566..3dfa5a9d 100644 --- a/demo/resque.php +++ b/demo/resque.php @@ -4,5 +4,4 @@ require 'job.php'; require 'php_error_job.php'; -require '../bin/resque'; -?> \ No newline at end of file +require '../bin/resque.php'; \ No newline at end of file diff --git a/lib/Resque.php b/lib/Resque.php index 2e459f0e..d65680b7 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -122,20 +122,21 @@ public static function pop($queue) } /** - * Pop an item off the end of the specified queue, decode it and - * return it. + * Pop an item off the end of the specified queues, using blocking list pop, + * decode it and return it. * - * @param string $queue The name of the queue to fetch an item from. - * @return array Decoded item from the queue. + * @param array $queues + * @param int $timeout + * @return null|array Decoded item from the queue. */ - public static function blpop($queues, $interval = null) + public static function blpop(array $queues, $timeout) { $list = array(); foreach($queues AS $queue) { $list[] = 'queue:' . $queue; } - $item = self::redis()->blpop($list, $interval ? (int)$interval : Resque::DEFAULT_INTERVAL); + $item = self::redis()->blpop($list, (int)$timeout); if(!$item) { return; @@ -186,9 +187,9 @@ public static function enqueue($queue, $class, $args = null, $trackStatus = fals * @param string $queue Queue to fetch next available job from. * @return Resque_Job Instance of Resque_Job to be processed, false if none or error. */ - public static function reserve($queue, $interval = null) + public static function reserve($queue) { - return Resque_Job::reserve($queue, $interval); + return Resque_Job::reserve($queue); } /** diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 0b1f01ed..ff1dd5c6 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -89,21 +89,20 @@ public static function reserve($queue) } /** - * Find the next available job from the specified queue and return an - * instance of Resque_Job for it. + * Find the next available job from the specified queues using blocking list pop + * and return an instance of Resque_Job for it. * - * @param string $queue The name of the queue to check for a job in. + * @param array $queues + * @param int $timeout * @return null|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. */ - public static function reserveBlocking($queues, $interval = null) + public static function reserveBlocking(array $queues, $timeout = null) { - $payload = Resque::blpop($queues, $interval); + $payload = Resque::blpop($queues, $timeout); if(!is_array($payload)) { return false; } - var_dump($payload); - return new Resque_Job($payload->queue, $payload); } diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 03487f58..3a730d84 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -147,13 +147,52 @@ public function __construct($queues) * * @param int $interval How often to check for new jobs across the queues. */ - public function work($interval = Resque::DEFAULT_INTERVAL) + public function work($interval = Resque::DEFAULT_INTERVAL, $blocking = false) { $this->updateProcLine('Starting'); $this->startup(); - while($job = $this->reserveBlocking($interval)) { - $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); + while(true) { + if($this->shutdown) { + break; + } + + // Attempt to find and reserve a job + $job = false; + if(!$this->paused) { + if($blocking === true) { + $this->log('Starting blocking with timeout of ' . $interval, self::LOG_VERBOSE); + $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with blocking timeout ' . $interval); + } else { + $this->log('Starting with interval of ' . $interval, self::LOG_VERBOSE); + $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); + } + + $job = $this->reserve($blocking, $interval); + } + + if(!$job) { + // For an interval of 0, break now - helps with unit testing etc + if($interval == 0) { + break; + } + + if($blocking === false) + { + // If no job was found, we sleep for $interval before continuing and checking again + $this->log('Sleeping for ' . $interval, self::LOG_VERBOSE); + if($this->paused) { + $this->updateProcLine('Paused'); + } + else { + $this->updateProcLine('Waiting for ' . implode(',', $this->queues)); + } + + usleep($interval * 1000000); + } + + continue; + } $this->log('got ' . $job); Resque_Event::trigger('beforeFork', $job); @@ -190,14 +229,6 @@ public function work($interval = Resque::DEFAULT_INTERVAL) $this->child = null; $this->doneWorking(); - - if($this->shutdown) { - break; - } - - if($this->paused) { - break; - } } $this->unregisterWorker(); @@ -225,44 +256,32 @@ public function perform(Resque_Job $job) } /** - * Attempt to find a job from the top of one of the queues for this worker. - * - * @return object|boolean Instance of Resque_Job if a job is found, false if not. + * @param bool $blocking + * @param int $timeout + * @return object|boolean Instance of Resque_Job if a job is found, false if not. */ - public function reserve() + public function reserve($blocking = false, $timeout = null) { $queues = $this->queues(); if(!is_array($queues)) { return; } - foreach($queues as $queue) { - $this->log('Checking ' . $queue, self::LOG_VERBOSE); - $job = Resque_Job::reserve($queue); + + if($blocking === true) { + $job = Resque_Job::reserveBlocking($queues, $timeout); if($job) { - $this->log('Found job on ' . $queue, self::LOG_VERBOSE); + $this->log('Found job on ' . $job->queue, self::LOG_VERBOSE); return $job; } - } - - return false; - } - - /** - * Attempt to find a job from the top of one of the queues for this worker. - * - * @return object|boolean Instance of Resque_Job if a job is found, false if not. - */ - public function reserveBlocking($interval = null) - { - $queues = $this->queues(); - if(!is_array($queues)) { - return; - } - - $job = Resque_Job::reserveBlocking($queues, $interval); - if($job) { - $this->log('Found job on ' . $job->queue, self::LOG_VERBOSE); - return $job; + } else { + foreach($queues as $queue) { + $this->log('Checking ' . $queue, self::LOG_VERBOSE); + $job = Resque_Job::reserve($queue); + if($job) { + $this->log('Found job on ' . $queue, self::LOG_VERBOSE); + return $job; + } + } } return false; diff --git a/test/Resque/Tests/JobStatusTest.php b/test/Resque/Tests/JobStatusTest.php index 3a12b4b3..68a25ff4 100644 --- a/test/Resque/Tests/JobStatusTest.php +++ b/test/Resque/Tests/JobStatusTest.php @@ -8,6 +8,11 @@ */ class Resque_Tests_JobStatusTest extends Resque_Tests_TestCase { + /** + * @var \Resque_Worker + */ + protected $worker; + public function setUp() { parent::setUp(); @@ -36,6 +41,7 @@ public function testQueuedJobReturnsQueuedStatus() $status = new Resque_Job_Status($token); $this->assertEquals(Resque_Job_Status::STATUS_WAITING, $status->get()); } + public function testRunningJobReturnsRunningStatus() { $token = Resque::enqueue('jobs', 'Failing_Job', null, true); From 66fec608a1efc499c151e5c7790626fc235ed44f Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Wed, 13 Mar 2013 13:03:19 +0100 Subject: [PATCH 086/194] Fixed unit test --- lib/Resque/Worker.php | 1 - test/Resque/Tests/WorkerTest.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 3a730d84..870d4c8c 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -164,7 +164,6 @@ public function work($interval = Resque::DEFAULT_INTERVAL, $blocking = false) $this->log('Starting blocking with timeout of ' . $interval, self::LOG_VERBOSE); $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with blocking timeout ' . $interval); } else { - $this->log('Starting with interval of ' . $interval, self::LOG_VERBOSE); $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); } diff --git a/test/Resque/Tests/WorkerTest.php b/test/Resque/Tests/WorkerTest.php index b0001c9e..1ab7dd27 100644 --- a/test/Resque/Tests/WorkerTest.php +++ b/test/Resque/Tests/WorkerTest.php @@ -257,7 +257,7 @@ public function testBlockingListPop() Resque::enqueue('jobs', 'Test_Job_2'); $i = 1; - while($job = $worker->reserve(60)) + while($job = $worker->reserve(true, 1)) { $this->assertEquals('Test_Job_' . $i, $job->payload['class']); From 01c291f367cb5392146268dee4cb68abec6912c1 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Tue, 26 Mar 2013 13:59:33 +0100 Subject: [PATCH 087/194] Added a PREFIX environment variable to set the Resque prefix --- README.md | 8 ++++++++ bin/resque | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/README.md b/README.md index 8e119885..bfdc302a 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,13 @@ the `COUNT` environment variable: $ COUNT=5 bin/resque +### Custom prefix ### + +When you have multiple apps using the same Redis database it is better to +use a custom prefix to separate the Resque data: + + $ PREFIX=my-app-name bin/resque + ### Forking ### Similarly to the Ruby versions, supported platforms will immediately @@ -371,3 +378,4 @@ Called after a job has been queued using the `Resque::enqueue` method. Arguments * Matt Heath * jjfrey * scragg0x +* ruudk diff --git a/bin/resque b/bin/resque index 78befad4..2b605ce6 100644 --- a/bin/resque +++ b/bin/resque @@ -71,6 +71,12 @@ if(!empty($COUNT) && $COUNT > 1) { $count = $COUNT; } +$PREFIX = getenv('PREFIX'); +if(!empty($PREFIX)) { + fwrite(STDOUT, '*** Prefix set to '.$PREFIX."\n"); + Resque_Redis::prefix($PREFIX); +} + if($count > 1) { for($i = 0; $i < $count; ++$i) { $pid = Resque::fork(); From 4ff0c51d40970810e1931305eca7d093092d4d0b Mon Sep 17 00:00:00 2001 From: Rajib Ahmed Date: Wed, 27 Mar 2013 16:45:05 +0100 Subject: [PATCH 088/194] Added PCNTL extension check on composer file --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 32f92ad9..d94ef1a6 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ ], "require": { "php": ">=5.3.0", + "ext-pcntl": "*", "colinmollenhour/credis": "dev-master" }, "suggest": { @@ -36,4 +37,4 @@ "Resque": "lib" } } -} \ No newline at end of file +} From 24f22c9065313581374d1ecaaa893369879f2bbd Mon Sep 17 00:00:00 2001 From: Matteo Giachino Date: Mon, 15 Apr 2013 22:53:17 +0300 Subject: [PATCH 089/194] Update README.md updated link to the new resque repo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bfdc302a..3d75992e 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ I am a kiss-ass), and written in Ruby. What you're seeing here is an almost direct port of the Resque worker and enqueue system to PHP. For more information on Resque, visit the official GitHub project: - + For further information, see the launch post on the GitHub blog: From e4ea683def8f81f17cd8dd2f44e596b87f72bcad Mon Sep 17 00:00:00 2001 From: CyrilMazur Date: Tue, 16 Apr 2013 13:07:03 -0300 Subject: [PATCH 090/194] Update Job.php Previous code was encapsulating $args in an additional array, and thus breaking the new job $args. --- lib/Resque/Job.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 82b11bc9..7581ae35 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -226,7 +226,7 @@ public function recreate() $monitor = true; } - return self::create($this->queue, $this->payload['class'], $this->payload['args'], $monitor); + return self::create($this->queue, $this->payload['class'], $this->getArguments(), $monitor); } /** From 3798fa3ba676b0728391dacffef9061b4000b69d Mon Sep 17 00:00:00 2001 From: Daniel Hunsaker Date: Thu, 9 May 2013 16:27:50 -0600 Subject: [PATCH 091/194] Added enqueue failure detection If a job fails to be enqueued, it would be useful to know it. So now Resque actually tells us whether the enqueue action was successful or if it failed. If your job ID comes back as FALSE, it didn't enqueue. Signed-off-by: Daniel Hunsaker --- lib/Resque.php | 6 +++++- lib/Resque/Job.php | 7 +++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index fa22ed1f..75b8d527 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -98,7 +98,11 @@ public static function fork() public static function push($queue, $item) { self::redis()->sadd('queues', $queue); - self::redis()->rpush('queue:' . $queue, json_encode($item)); + if (self::redis()->rpush('queue:' . $queue, json_encode($item)) < 1) + { + return FALSE; + } + return TRUE; } /** diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 82b11bc9..fc84e1ed 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -58,11 +58,14 @@ public static function create($queue, $class, $args = null, $monitor = false) ); } $id = md5(uniqid('', true)); - Resque::push($queue, array( + if ( ! Resque::push($queue, array( 'class' => $class, 'args' => array($args), 'id' => $id, - )); + ))) + { + return FALSE; + } if($monitor) { Resque_Job_Status::create($id); From 3f5937a5f86b0b6f0a1a7bd63bcaff7674e982ad Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sun, 12 May 2013 14:55:20 +1000 Subject: [PATCH 092/194] test against version 2.2.3 of phpredis --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index cdb44788..d8dd5f89 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ env: - REDIS_STANDALONE=0 - REDIS_STANDALONE=1 before_script: - - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then wget https://github.com/nicolasff/phpredis/archive/2.2.2.zip -O php-redis.zip && unzip php-redis.zip; fi" - - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then cd phpredis-2.2.2/ && phpize && ./configure && make && make install; fi" + - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then wget https://github.com/nicolasff/phpredis/archive/2.2.3.zip -O php-redis.zip && unzip php-redis.zip; fi" + - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then cd phpredis-2.2.3/ && phpize && ./configure && make && make install; fi" - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then echo \"extension=redis.so\" >> `php --ini | grep \"Loaded Configuration\" | sed -e \"s|.*:\s*||\"`; fi" - - composer install \ No newline at end of file + - composer install From b31830c0bf5c65fe95cf89a6136b74b936ee6098 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sun, 12 May 2013 15:40:35 +1000 Subject: [PATCH 093/194] when testing job recreation, compare the results of ->getArguments() --- test/Resque/Tests/JobTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Resque/Tests/JobTest.php b/test/Resque/Tests/JobTest.php index 5d93d6fd..688c2654 100644 --- a/test/Resque/Tests/JobTest.php +++ b/test/Resque/Tests/JobTest.php @@ -95,7 +95,7 @@ public function testRecreatedJobMatchesExistingJob() $newJob = Resque_Job::reserve('jobs'); $this->assertEquals($job->payload['class'], $newJob->payload['class']); - $this->assertEquals($job->payload['args'], $newJob->getArguments()); + $this->assertEquals($job->getArguments(), $newJob->getArguments()); } From 8d1a9a55649a9375af93ecff4c209312bbaf67ff Mon Sep 17 00:00:00 2001 From: Daniel Hunsaker Date: Sun, 12 May 2013 12:58:18 -0600 Subject: [PATCH 094/194] Updated to match coding style. Signed-off-by: Daniel Hunsaker --- lib/Resque.php | 8 ++++---- lib/Resque/Job.php | 7 +++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index 75b8d527..a463bea9 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -98,11 +98,11 @@ public static function fork() public static function push($queue, $item) { self::redis()->sadd('queues', $queue); - if (self::redis()->rpush('queue:' . $queue, json_encode($item)) < 1) - { - return FALSE; + $length = self::redis()->rpush('queue:' . $queue, json_encode($item)); + if ($length < 1) { + return false; } - return TRUE; + return true; } /** diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index fc84e1ed..d2a4e84c 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -58,13 +58,12 @@ public static function create($queue, $class, $args = null, $monitor = false) ); } $id = md5(uniqid('', true)); - if ( ! Resque::push($queue, array( + if (!Resque::push($queue, array( 'class' => $class, 'args' => array($args), 'id' => $id, - ))) - { - return FALSE; + ))) { + return false; } if($monitor) { From 4d5552867a30a314939209ba6b161b60db5c1d5e Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Fri, 24 Aug 2012 16:51:03 +0200 Subject: [PATCH 095/194] Basic support for blocking list pop --- lib/Resque.php | 16 ++++++++++++---- lib/Resque/Job.php | 6 +++--- lib/Resque/Redis.php | 1 + lib/Resque/Worker.php | 42 +++++++++++++++++++++--------------------- 4 files changed, 37 insertions(+), 28 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index a463bea9..7478fa41 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -10,6 +10,8 @@ class Resque { const VERSION = '1.2'; + const DEFAULT_INTERVAL = 5; + /** * @var Resque_Redis Instance of Resque_Redis that talks to redis. */ @@ -112,14 +114,19 @@ public static function push($queue, $item) * @param string $queue The name of the queue to fetch an item from. * @return array Decoded item from the queue. */ - public static function pop($queue) + public static function pop($queue, $interval = null) { - $item = self::redis()->lpop('queue:' . $queue); + if($interval == null) { + $item = self::redis()->lpop('queue:' . $queue); + } else { + $item = self::redis()->blpop('queue:' . $queue, $interval ?: Resque::DEFAULT_INTERVAL); + } + if(!$item) { return; } - return json_decode($item, true); + return json_decode($interval == 0 ? $item : $item[1], true); } /** @@ -164,8 +171,9 @@ public static function enqueue($queue, $class, $args = null, $trackStatus = fals * @param string $queue Queue to fetch next available job from. * @return Resque_Job Instance of Resque_Job to be processed, false if none or error. */ - public static function reserve($queue) + public static function reserve($queue, $interval = null) { + require_once dirname(__FILE__) . '/Resque/Job.php'; return Resque_Job::reserve($queue); } diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 8cedd4be..618b118a 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -80,9 +80,9 @@ public static function create($queue, $class, $args = null, $monitor = false) * @param string $queue The name of the queue to check for a job in. * @return null|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. */ - public static function reserve($queue) + public static function reserve($queue, $interval = null) { - $payload = Resque::pop($queue); + $payload = Resque::pop($queue, $interval); if(!is_array($payload)) { return false; } @@ -153,7 +153,7 @@ public function getInstance() ); } - $this->instance = new $this->payload['class'](); + $this->instance = new $this->payload['class']; $this->instance->job = $this; $this->instance->args = $this->getArguments(); $this->instance->queue = $this->queue; diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index bbb0643c..44471461 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -47,6 +47,7 @@ class Resque_Redis 'lset', 'lrem', 'lpop', + 'blpop', 'rpop', 'sadd', 'srem', diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 45852bb6..204aae68 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -147,7 +147,7 @@ public function __construct($queues) * * @param int $interval How often to check for new jobs across the queues. */ - public function work($interval = 5) + public function work($interval = Resque::DEFAULT_INTERVAL) { $this->updateProcLine('Starting'); $this->startup(); @@ -160,25 +160,25 @@ public function work($interval = 5) // Attempt to find and reserve a job $job = false; if(!$this->paused) { - $job = $this->reserve(); + $job = $this->reserve($interval); } - if(!$job) { - // For an interval of 0, break now - helps with unit testing etc - if($interval == 0) { - break; - } - // If no job was found, we sleep for $interval before continuing and checking again - $this->log('Sleeping for ' . $interval, self::LOG_VERBOSE); - if($this->paused) { - $this->updateProcLine('Paused'); - } - else { - $this->updateProcLine('Waiting for ' . implode(',', $this->queues)); - } - usleep($interval * 1000000); - continue; - } + $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); + + if(!$job) { + // For an interval of 0, break now - helps with unit testing etc + if($interval == 0) { + break; + } + + // If no job was found, we sleep for $interval before continuing and checking again + if($this->paused) { + $this->updateProcLine('Paused'); + usleep($interval * 1000000); //it's paused, so don't hog redis with requests. + } + + continue; + } $this->log('got ' . $job); Resque_Event::trigger('beforeFork', $job); @@ -246,15 +246,15 @@ public function perform(Resque_Job $job) * * @return object|boolean Instance of Resque_Job if a job is found, false if not. */ - public function reserve() + public function reserve($interval = null) { $queues = $this->queues(); if(!is_array($queues)) { return; } foreach($queues as $queue) { - $this->log('Checking ' . $queue, self::LOG_VERBOSE); - $job = Resque_Job::reserve($queue); + $this->log('Checking ' . $queue . ' with interval ' . $interval, self::LOG_VERBOSE); + $job = Resque_Job::reserve($queue, $interval); if($job) { $this->log('Found job on ' . $queue, self::LOG_VERBOSE); return $job; From 15324ca410ebc963e116a9b3815b94dbc026d388 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Mon, 10 Sep 2012 10:23:18 +0200 Subject: [PATCH 096/194] Fixed bug --- lib/Resque.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque.php b/lib/Resque.php index 7478fa41..928ef5e7 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -119,7 +119,7 @@ public static function pop($queue, $interval = null) if($interval == null) { $item = self::redis()->lpop('queue:' . $queue); } else { - $item = self::redis()->blpop('queue:' . $queue, $interval ?: Resque::DEFAULT_INTERVAL); + $item = self::redis()->blpop('queue:' . $queue, $interval ? $interval : Resque::DEFAULT_INTERVAL); } if(!$item) { From e541fa9b70c944b9a7f90fc636531db6c88c2e54 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Tue, 12 Mar 2013 09:55:03 +0100 Subject: [PATCH 097/194] Added test for blpop --- test/Resque/Tests/WorkerTest.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/Resque/Tests/WorkerTest.php b/test/Resque/Tests/WorkerTest.php index b2f0e000..b0001c9e 100644 --- a/test/Resque/Tests/WorkerTest.php +++ b/test/Resque/Tests/WorkerTest.php @@ -247,4 +247,27 @@ public function testWorkerFailsUncompletedJobsOnExit() $this->assertEquals(1, Resque_Stat::get('failed')); } + + public function testBlockingListPop() + { + $worker = new Resque_Worker('jobs'); + $worker->registerWorker(); + + Resque::enqueue('jobs', 'Test_Job_1'); + Resque::enqueue('jobs', 'Test_Job_2'); + + $i = 1; + while($job = $worker->reserve(60)) + { + $this->assertEquals('Test_Job_' . $i, $job->payload['class']); + + if($i == 2) { + break; + } + + $i++; + } + + $this->assertEquals(2, $i); + } } \ No newline at end of file From b8f98eecd2f4cfad157c28a7a26f6122d679ef64 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Tue, 12 Mar 2013 11:18:37 +0100 Subject: [PATCH 098/194] WIP --- bin/resque | 1 - demo/job.php | 5 +- demo/queue.php | 2 +- lib/Resque.php | 33 +++++++-- lib/Resque/Job.php | 49 +++++++++---- lib/Resque/Redis.php | 8 ++- lib/Resque/Worker.php | 158 ++++++++++++++++++++++-------------------- 7 files changed, 152 insertions(+), 104 deletions(-) diff --git a/bin/resque b/bin/resque index 2b605ce6..fbae329d 100644 --- a/bin/resque +++ b/bin/resque @@ -1,4 +1,3 @@ -#!/usr/bin/env php '); + sleep(1); + fwrite(STDOUT, 'Job ended!' . PHP_EOL); } } ?> \ No newline at end of file diff --git a/demo/queue.php b/demo/queue.php index 95ff5b05..393df87e 100644 --- a/demo/queue.php +++ b/demo/queue.php @@ -14,6 +14,6 @@ ), ); -$jobId = Resque::enqueue('default', $argv[1], $args, true); +$jobId = Resque::enqueue($argv[1], $argv[2], $args, true); echo "Queued job ".$jobId."\n\n"; ?> \ No newline at end of file diff --git a/lib/Resque.php b/lib/Resque.php index 928ef5e7..c7ddf4cc 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -114,21 +114,40 @@ public static function push($queue, $item) * @param string $queue The name of the queue to fetch an item from. * @return array Decoded item from the queue. */ - public static function pop($queue, $interval = null) + public static function pop($queue) { - if($interval == null) { - $item = self::redis()->lpop('queue:' . $queue); - } else { - $item = self::redis()->blpop('queue:' . $queue, $interval ? $interval : Resque::DEFAULT_INTERVAL); - } + $item = self::redis()->lpop('queue:' . $queue); if(!$item) { return; } - return json_decode($interval == 0 ? $item : $item[1], true); + return json_decode($item, true); } + /** + * Pop an item off the end of the specified queue, decode it and + * return it. + * + * @param string $queue The name of the queue to fetch an item from. + * @return array Decoded item from the queue. + */ + public static function blpop($queues, $interval = null) + { + $list = array(); + foreach($queues AS $queue) { + $list[] = 'queue:' . $queue; + } + + $item = self::redis()->blpop($list, $interval ? (int)$interval : Resque::DEFAULT_INTERVAL); + + if(!$item) { + return; + } + + return json_decode($item[1], true); + } + /** * Return the size (number of pending jobs) of the specified queue. * diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 618b118a..e2fb60e8 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -73,22 +73,41 @@ public static function create($queue, $class, $args = null, $monitor = false) return $id; } - /** - * Find the next available job from the specified queue and return an - * instance of Resque_Job for it. - * - * @param string $queue The name of the queue to check for a job in. - * @return null|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. - */ - public static function reserve($queue, $interval = null) - { - $payload = Resque::pop($queue, $interval); - if(!is_array($payload)) { - return false; - } + /** + * Find the next available job from the specified queue and return an + * instance of Resque_Job for it. + * + * @param string $queue The name of the queue to check for a job in. + * @return null|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. + */ + public static function reserve($queue) + { + $payload = Resque::pop($queue); + if(!is_array($payload)) { + return false; + } - return new Resque_Job($queue, $payload); - } + return new Resque_Job($queue, $payload); + } + + /** + * Find the next available job from the specified queue and return an + * instance of Resque_Job for it. + * + * @param string $queue The name of the queue to check for a job in. + * @return null|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. + */ + public static function reserveBlocking($queues, $interval = null) + { + $payload = Resque::blpop($queues, $interval); + if(!is_array($payload)) { + return false; + } + + var_dump($payload); + + return new Resque_Job($payload->queue, $payload); + } /** * Update the status of the current job. diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 44471461..6cef3d2d 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -143,7 +143,13 @@ public function __construct($server, $database = null) */ public function __call($name, $args) { if(in_array($name, $this->keyCommands)) { - $args[0] = self::$defaultNamespace . $args[0]; + if(is_array($args[0])) { + foreach($args[0] AS $i => $v) { + $args[0][$i] = self::$defaultNamespace . $v; + } + } else { + $args[0] = self::$defaultNamespace . $args[0]; + } } try { return $this->driver->__call($name, $args); diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 204aae68..03487f58 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -152,70 +152,53 @@ public function work($interval = Resque::DEFAULT_INTERVAL) $this->updateProcLine('Starting'); $this->startup(); - while(true) { - if($this->shutdown) { - break; - } + while($job = $this->reserveBlocking($interval)) { + $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); - // Attempt to find and reserve a job - $job = false; - if(!$this->paused) { - $job = $this->reserve($interval); - } + $this->log('got ' . $job); + Resque_Event::trigger('beforeFork', $job); + $this->workingOn($job); - $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); + $this->child = Resque::fork(); - if(!$job) { - // For an interval of 0, break now - helps with unit testing etc - if($interval == 0) { - break; + // Forked and we're the child. Run the job. + if ($this->child === 0 || $this->child === false) { + $status = 'Processing ' . $job->queue . ' since ' . strftime('%F %T'); + $this->updateProcLine($status); + $this->log($status, self::LOG_VERBOSE); + $this->perform($job); + if ($this->child === 0) { + exit(0); } + } - // If no job was found, we sleep for $interval before continuing and checking again - if($this->paused) { - $this->updateProcLine('Paused'); - usleep($interval * 1000000); //it's paused, so don't hog redis with requests. + if($this->child > 0) { + // Parent process, sit and wait + $status = 'Forked ' . $this->child . ' at ' . strftime('%F %T'); + $this->updateProcLine($status); + $this->log($status, self::LOG_VERBOSE); + + // Wait until the child process finishes before continuing + pcntl_wait($status); + $exitStatus = pcntl_wexitstatus($status); + if($exitStatus !== 0) { + $job->fail(new Resque_Job_DirtyExitException( + 'Job exited with exit code ' . $exitStatus + )); } - - continue; } - $this->log('got ' . $job); - Resque_Event::trigger('beforeFork', $job); - $this->workingOn($job); - - $this->child = Resque::fork(); - - // Forked and we're the child. Run the job. - if ($this->child === 0 || $this->child === false) { - $status = 'Processing ' . $job->queue . ' since ' . strftime('%F %T'); - $this->updateProcLine($status); - $this->log($status, self::LOG_VERBOSE); - $this->perform($job); - if ($this->child === 0) { - exit(0); - } - } - - if($this->child > 0) { - // Parent process, sit and wait - $status = 'Forked ' . $this->child . ' at ' . strftime('%F %T'); - $this->updateProcLine($status); - $this->log($status, self::LOG_VERBOSE); - - // Wait until the child process finishes before continuing - pcntl_wait($status); - $exitStatus = pcntl_wexitstatus($status); - if($exitStatus !== 0) { - $job->fail(new Resque_Job_DirtyExitException( - 'Job exited with exit code ' . $exitStatus - )); - } - } + $this->child = null; + $this->doneWorking(); - $this->child = null; - $this->doneWorking(); - } + if($this->shutdown) { + break; + } + + if($this->paused) { + break; + } + } $this->unregisterWorker(); } @@ -241,28 +224,49 @@ public function perform(Resque_Job $job) $this->log('done ' . $job); } - /** - * Attempt to find a job from the top of one of the queues for this worker. - * - * @return object|boolean Instance of Resque_Job if a job is found, false if not. - */ - public function reserve($interval = null) - { - $queues = $this->queues(); - if(!is_array($queues)) { - return; - } - foreach($queues as $queue) { - $this->log('Checking ' . $queue . ' with interval ' . $interval, self::LOG_VERBOSE); - $job = Resque_Job::reserve($queue, $interval); - if($job) { - $this->log('Found job on ' . $queue, self::LOG_VERBOSE); - return $job; - } - } - - return false; - } + /** + * Attempt to find a job from the top of one of the queues for this worker. + * + * @return object|boolean Instance of Resque_Job if a job is found, false if not. + */ + public function reserve() + { + $queues = $this->queues(); + if(!is_array($queues)) { + return; + } + foreach($queues as $queue) { + $this->log('Checking ' . $queue, self::LOG_VERBOSE); + $job = Resque_Job::reserve($queue); + if($job) { + $this->log('Found job on ' . $queue, self::LOG_VERBOSE); + return $job; + } + } + + return false; + } + + /** + * Attempt to find a job from the top of one of the queues for this worker. + * + * @return object|boolean Instance of Resque_Job if a job is found, false if not. + */ + public function reserveBlocking($interval = null) + { + $queues = $this->queues(); + if(!is_array($queues)) { + return; + } + + $job = Resque_Job::reserveBlocking($queues, $interval); + if($job) { + $this->log('Found job on ' . $job->queue, self::LOG_VERBOSE); + return $job; + } + + return false; + } /** * Return an array containing all of the queues that this worker should use From 86ae77811d6515a120ea01b4a33761b61da61413 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Wed, 13 Mar 2013 12:41:32 +0100 Subject: [PATCH 099/194] Working blocking list pop :) --- bin/resque | 1 + bin/resque.php | 105 +++++++ composer.lock | 416 +++++++++++++++++++++++++++- demo/bad_job.php | 3 +- demo/check_status.php | 3 +- demo/job.php | 3 +- demo/long_job.php | 3 +- demo/php_error_job.php | 3 +- demo/queue.php | 3 +- demo/resque.php | 3 +- lib/Resque.php | 16 +- lib/Resque/Job.php | 13 +- lib/Resque/Worker.php | 99 ++++--- test/Resque/Tests/JobStatusTest.php | 6 + 14 files changed, 604 insertions(+), 73 deletions(-) mode change 100644 => 100755 bin/resque create mode 100644 bin/resque.php diff --git a/bin/resque b/bin/resque old mode 100644 new mode 100755 index fbae329d..2b605ce6 --- a/bin/resque +++ b/bin/resque @@ -1,3 +1,4 @@ +#!/usr/bin/env php 1) { + $count = $COUNT; +} + +if($count > 1) { + for($i = 0; $i < $count; ++$i) { + $pid = Resque::fork(); + if($pid == -1) { + die("Could not fork worker ".$i."\n"); + } + // Child, start the worker + else if(!$pid) { + $queues = explode(',', $QUEUE); + $worker = new Resque_Worker($queues); + $worker->logLevel = $logLevel; + fwrite(STDOUT, '*** Starting worker '.$worker."\n"); + $worker->work($interval, $BLOCKING); + break; + } + } +} +// Start a single worker +else { + $queues = explode(',', $QUEUE); + $worker = new Resque_Worker($queues); + $worker->logLevel = $logLevel; + + $PIDFILE = getenv('PIDFILE'); + if ($PIDFILE) { + file_put_contents($PIDFILE, getmypid()) or + die('Could not write PID information to ' . $PIDFILE); + } + + fwrite(STDOUT, '*** Starting worker '.$worker."\n"); + $worker->work($interval, $BLOCKING); +} \ No newline at end of file diff --git a/composer.lock b/composer.lock index 877c2434..760d4cf5 100644 --- a/composer.lock +++ b/composer.lock @@ -18,7 +18,6 @@ "require": { "php": ">=5.3.0" }, - "time": "2013-01-12 10:15:31", "type": "library", "autoload": { "classmap": [ @@ -39,15 +38,424 @@ "homepage": "https://github.com/colinmollenhour/credis", "support": { "source": "https://github.com/chrisboulton/credis/tree/master" - } + }, + "time": "2013-01-12 10:15:31" + } + ], + "packages-dev": [ + { + "name": "phpunit/php-code-coverage", + "version": "1.2.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "1.2.9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.9", + "reference": "1.2.9", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": ">=1.3.0@stable", + "phpunit/php-text-template": ">=1.1.1@stable", + "phpunit/php-token-stream": ">=1.1.3@stable" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.0.5" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2013-02-26 18:55:56" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.3.3", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "1.3.3" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-file-iterator/zipball/1.3.3", + "reference": "1.3.3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "File/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2012-10-11 04:44:38" + }, + { + "name": "phpunit/php-text-template", + "version": "1.1.4", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-text-template.git", + "reference": "1.1.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-text-template/zipball/1.1.4", + "reference": "1.1.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "Text/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2012-10-31 11:15:28" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.4", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-timer.git", + "reference": "1.0.4" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-timer/zipball/1.0.4", + "reference": "1.0.4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "timer" + ], + "time": "2012-10-11 04:45:58" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.1.5", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/php-token-stream.git", + "reference": "1.1.5" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/php-token-stream/zipball/1.1.5", + "reference": "1.1.5", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "tokenizer" + ], + "time": "2012-10-11 04:47:14" + }, + { + "name": "phpunit/phpunit", + "version": "3.7.18", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "3.7.18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.18", + "reference": "3.7.18", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpunit/php-code-coverage": ">=1.2.1,<1.3.0", + "phpunit/php-file-iterator": ">=1.3.1", + "phpunit/php-text-template": ">=1.1.1", + "phpunit/php-timer": ">=1.0.2,<1.1.0", + "phpunit/phpunit-mock-objects": ">=1.2.0,<1.3.0", + "symfony/yaml": ">=2.2.0" + }, + "require-dev": { + "pear-pear/pear": "1.9.4" + }, + "suggest": { + "ext-json": "*", + "ext-simplexml": "*", + "ext-tokenizer": "*", + "phpunit/php-invoker": ">=1.1.0,<1.2.0" + }, + "bin": [ + "composer/bin/phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "", + "../../symfony/yaml/" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2013-03-07 21:45:39" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "1.2.3", + "source": { + "type": "git", + "url": "git://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "1.2.3" + }, + "dist": { + "type": "zip", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects/archive/1.2.3.zip", + "reference": "1.2.3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-text-template": ">=1.1.1@stable" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2013-01-13 10:24:48" + }, + { + "name": "symfony/yaml", + "version": "v2.2.0", + "target-dir": "Symfony/Component/Yaml", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "v2.2.0-RC3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.2.0-RC3", + "reference": "v2.2.0-RC3", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "http://symfony.com/", + "time": "2013-01-27 16:49:19" } ], - "packages-dev": null, "aliases": [ ], "minimum-stability": "stable", "stability-flags": { "colinmollenhour/credis": 20 - } + }, + "platform": { + "php": ">=5.3.0" + }, + "platform-dev": [ + + ] } diff --git a/demo/bad_job.php b/demo/bad_job.php index bc126209..cd719cc2 100644 --- a/demo/bad_job.php +++ b/demo/bad_job.php @@ -5,5 +5,4 @@ public function perform() { throw new Exception('Unable to run this job!'); } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/demo/check_status.php b/demo/check_status.php index 061a83a9..645bf6d9 100644 --- a/demo/check_status.php +++ b/demo/check_status.php @@ -17,5 +17,4 @@ while(true) { fwrite(STDOUT, "Status of ".$argv[1]." is: ".$status->get()."\n"); sleep(1); -} -?> +} \ No newline at end of file diff --git a/demo/job.php b/demo/job.php index ec3d143e..ddda8932 100644 --- a/demo/job.php +++ b/demo/job.php @@ -7,5 +7,4 @@ public function perform() sleep(1); fwrite(STDOUT, 'Job ended!' . PHP_EOL); } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/demo/long_job.php b/demo/long_job.php index 8c9f0f94..1cfe5cb0 100644 --- a/demo/long_job.php +++ b/demo/long_job.php @@ -5,5 +5,4 @@ public function perform() { sleep(600); } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/demo/php_error_job.php b/demo/php_error_job.php index 93bf2bca..98244059 100644 --- a/demo/php_error_job.php +++ b/demo/php_error_job.php @@ -5,5 +5,4 @@ public function perform() { callToUndefinedFunction(); } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/demo/queue.php b/demo/queue.php index 393df87e..52f2f0ba 100644 --- a/demo/queue.php +++ b/demo/queue.php @@ -15,5 +15,4 @@ ); $jobId = Resque::enqueue($argv[1], $argv[2], $args, true); -echo "Queued job ".$jobId."\n\n"; -?> \ No newline at end of file +echo "Queued job ".$jobId."\n\n"; \ No newline at end of file diff --git a/demo/resque.php b/demo/resque.php index cdaf7566..3dfa5a9d 100644 --- a/demo/resque.php +++ b/demo/resque.php @@ -4,5 +4,4 @@ require 'job.php'; require 'php_error_job.php'; -require '../bin/resque'; -?> \ No newline at end of file +require '../bin/resque.php'; \ No newline at end of file diff --git a/lib/Resque.php b/lib/Resque.php index c7ddf4cc..b7157672 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -126,20 +126,21 @@ public static function pop($queue) } /** - * Pop an item off the end of the specified queue, decode it and - * return it. + * Pop an item off the end of the specified queues, using blocking list pop, + * decode it and return it. * - * @param string $queue The name of the queue to fetch an item from. - * @return array Decoded item from the queue. + * @param array $queues + * @param int $timeout + * @return null|array Decoded item from the queue. */ - public static function blpop($queues, $interval = null) + public static function blpop(array $queues, $timeout) { $list = array(); foreach($queues AS $queue) { $list[] = 'queue:' . $queue; } - $item = self::redis()->blpop($list, $interval ? (int)$interval : Resque::DEFAULT_INTERVAL); + $item = self::redis()->blpop($list, (int)$timeout); if(!$item) { return; @@ -190,9 +191,8 @@ public static function enqueue($queue, $class, $args = null, $trackStatus = fals * @param string $queue Queue to fetch next available job from. * @return Resque_Job Instance of Resque_Job to be processed, false if none or error. */ - public static function reserve($queue, $interval = null) + public static function reserve($queue) { - require_once dirname(__FILE__) . '/Resque/Job.php'; return Resque_Job::reserve($queue); } diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index e2fb60e8..7d90d0af 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -91,21 +91,20 @@ public static function reserve($queue) } /** - * Find the next available job from the specified queue and return an - * instance of Resque_Job for it. + * Find the next available job from the specified queues using blocking list pop + * and return an instance of Resque_Job for it. * - * @param string $queue The name of the queue to check for a job in. + * @param array $queues + * @param int $timeout * @return null|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. */ - public static function reserveBlocking($queues, $interval = null) + public static function reserveBlocking(array $queues, $timeout = null) { - $payload = Resque::blpop($queues, $interval); + $payload = Resque::blpop($queues, $timeout); if(!is_array($payload)) { return false; } - var_dump($payload); - return new Resque_Job($payload->queue, $payload); } diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 03487f58..3a730d84 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -147,13 +147,52 @@ public function __construct($queues) * * @param int $interval How often to check for new jobs across the queues. */ - public function work($interval = Resque::DEFAULT_INTERVAL) + public function work($interval = Resque::DEFAULT_INTERVAL, $blocking = false) { $this->updateProcLine('Starting'); $this->startup(); - while($job = $this->reserveBlocking($interval)) { - $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); + while(true) { + if($this->shutdown) { + break; + } + + // Attempt to find and reserve a job + $job = false; + if(!$this->paused) { + if($blocking === true) { + $this->log('Starting blocking with timeout of ' . $interval, self::LOG_VERBOSE); + $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with blocking timeout ' . $interval); + } else { + $this->log('Starting with interval of ' . $interval, self::LOG_VERBOSE); + $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); + } + + $job = $this->reserve($blocking, $interval); + } + + if(!$job) { + // For an interval of 0, break now - helps with unit testing etc + if($interval == 0) { + break; + } + + if($blocking === false) + { + // If no job was found, we sleep for $interval before continuing and checking again + $this->log('Sleeping for ' . $interval, self::LOG_VERBOSE); + if($this->paused) { + $this->updateProcLine('Paused'); + } + else { + $this->updateProcLine('Waiting for ' . implode(',', $this->queues)); + } + + usleep($interval * 1000000); + } + + continue; + } $this->log('got ' . $job); Resque_Event::trigger('beforeFork', $job); @@ -190,14 +229,6 @@ public function work($interval = Resque::DEFAULT_INTERVAL) $this->child = null; $this->doneWorking(); - - if($this->shutdown) { - break; - } - - if($this->paused) { - break; - } } $this->unregisterWorker(); @@ -225,44 +256,32 @@ public function perform(Resque_Job $job) } /** - * Attempt to find a job from the top of one of the queues for this worker. - * - * @return object|boolean Instance of Resque_Job if a job is found, false if not. + * @param bool $blocking + * @param int $timeout + * @return object|boolean Instance of Resque_Job if a job is found, false if not. */ - public function reserve() + public function reserve($blocking = false, $timeout = null) { $queues = $this->queues(); if(!is_array($queues)) { return; } - foreach($queues as $queue) { - $this->log('Checking ' . $queue, self::LOG_VERBOSE); - $job = Resque_Job::reserve($queue); + + if($blocking === true) { + $job = Resque_Job::reserveBlocking($queues, $timeout); if($job) { - $this->log('Found job on ' . $queue, self::LOG_VERBOSE); + $this->log('Found job on ' . $job->queue, self::LOG_VERBOSE); return $job; } - } - - return false; - } - - /** - * Attempt to find a job from the top of one of the queues for this worker. - * - * @return object|boolean Instance of Resque_Job if a job is found, false if not. - */ - public function reserveBlocking($interval = null) - { - $queues = $this->queues(); - if(!is_array($queues)) { - return; - } - - $job = Resque_Job::reserveBlocking($queues, $interval); - if($job) { - $this->log('Found job on ' . $job->queue, self::LOG_VERBOSE); - return $job; + } else { + foreach($queues as $queue) { + $this->log('Checking ' . $queue, self::LOG_VERBOSE); + $job = Resque_Job::reserve($queue); + if($job) { + $this->log('Found job on ' . $queue, self::LOG_VERBOSE); + return $job; + } + } } return false; diff --git a/test/Resque/Tests/JobStatusTest.php b/test/Resque/Tests/JobStatusTest.php index 3a12b4b3..68a25ff4 100644 --- a/test/Resque/Tests/JobStatusTest.php +++ b/test/Resque/Tests/JobStatusTest.php @@ -8,6 +8,11 @@ */ class Resque_Tests_JobStatusTest extends Resque_Tests_TestCase { + /** + * @var \Resque_Worker + */ + protected $worker; + public function setUp() { parent::setUp(); @@ -36,6 +41,7 @@ public function testQueuedJobReturnsQueuedStatus() $status = new Resque_Job_Status($token); $this->assertEquals(Resque_Job_Status::STATUS_WAITING, $status->get()); } + public function testRunningJobReturnsRunningStatus() { $token = Resque::enqueue('jobs', 'Failing_Job', null, true); From f379d3a36d8685d72b86b3b740a85fcb17ee880d Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Wed, 13 Mar 2013 13:03:19 +0100 Subject: [PATCH 100/194] Fixed unit test --- lib/Resque/Worker.php | 1 - test/Resque/Tests/WorkerTest.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 3a730d84..870d4c8c 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -164,7 +164,6 @@ public function work($interval = Resque::DEFAULT_INTERVAL, $blocking = false) $this->log('Starting blocking with timeout of ' . $interval, self::LOG_VERBOSE); $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with blocking timeout ' . $interval); } else { - $this->log('Starting with interval of ' . $interval, self::LOG_VERBOSE); $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); } diff --git a/test/Resque/Tests/WorkerTest.php b/test/Resque/Tests/WorkerTest.php index b0001c9e..1ab7dd27 100644 --- a/test/Resque/Tests/WorkerTest.php +++ b/test/Resque/Tests/WorkerTest.php @@ -257,7 +257,7 @@ public function testBlockingListPop() Resque::enqueue('jobs', 'Test_Job_2'); $i = 1; - while($job = $worker->reserve(60)) + while($job = $worker->reserve(true, 1)) { $this->assertEquals('Test_Job_' . $i, $job->payload['class']); From bfbff5e58e92e96778c108086cf96df44bc9c5d6 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Wed, 29 May 2013 09:29:24 +0200 Subject: [PATCH 101/194] Unit tests pass --- lib/Resque.php | 12 +++++++++++- lib/Resque/Job.php | 7 ++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index b7157672..3ec80f76 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -146,7 +146,17 @@ public static function blpop(array $queues, $timeout) return; } - return json_decode($item[1], true); + /** + * Normally the Resque_Redis class returns queue names without the prefix + * But the blpop is a bit different. It returns the name as prefix:queue:name + * So we need to strip off the prefix:queue: part + */ + $queue = substr($item[0], strlen(self::redis()->getPrefix() . 'queue:')); + + return array( + 'queue' => $queue, + 'payload' => json_decode($item[1], true) + ); } /** diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 7d90d0af..63cb2036 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -100,12 +100,13 @@ public static function reserve($queue) */ public static function reserveBlocking(array $queues, $timeout = null) { - $payload = Resque::blpop($queues, $timeout); - if(!is_array($payload)) { + $item = Resque::blpop($queues, $timeout); + + if(!is_array($item)) { return false; } - return new Resque_Job($payload->queue, $payload); + return new Resque_Job($item['queue'], $item['payload']); } /** From f3dcc092d46d599186c9e04003de9e2d218e913c Mon Sep 17 00:00:00 2001 From: Aaron Bonner Date: Wed, 29 May 2013 15:57:39 +0100 Subject: [PATCH 102/194] Add type to $queue param in size()'s docblock --- lib/Resque.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque.php b/lib/Resque.php index a463bea9..2488d5eb 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -125,7 +125,7 @@ public static function pop($queue) /** * Return the size (number of pending jobs) of the specified queue. * - * @param $queue name of the queue to be checked for pending jobs + * @param string $queue name of the queue to be checked for pending jobs * * @return int The size of the queue. */ From ffff86c40ca68764fef0151a47ae711c7326b215 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Mon, 3 Jun 2013 18:09:54 +0200 Subject: [PATCH 103/194] Fixes bin/resque --- bin/resque | 106 +++++++++++++++++++++++++------------------------ bin/resque.php | 105 ------------------------------------------------ 2 files changed, 54 insertions(+), 157 deletions(-) delete mode 100644 bin/resque.php diff --git a/bin/resque b/bin/resque index 2b605ce6..f0f14294 100755 --- a/bin/resque +++ b/bin/resque @@ -3,40 +3,40 @@ // Find and initialize Composer $files = array( - __DIR__ . '/../../vendor/autoload.php', - __DIR__ . '/../../../autoload.php', - __DIR__ . '/../../../../autoload.php', - __DIR__ . '/../vendor/autoload.php', + __DIR__ . '/../../vendor/autoload.php', + __DIR__ . '/../../../autoload.php', + __DIR__ . '/../../../../autoload.php', + __DIR__ . '/../vendor/autoload.php', ); $found = false; foreach ($files as $file) { - if (file_exists($file)) { - require_once $file; - break; - } + if (file_exists($file)) { + require_once $file; + break; + } } if (!class_exists('Composer\Autoload\ClassLoader', false)) { - die( - 'You need to set up the project dependencies using the following commands:' . PHP_EOL . - 'curl -s http://getcomposer.org/installer | php' . PHP_EOL . - 'php composer.phar install' . PHP_EOL - ); + die( + 'You need to set up the project dependencies using the following commands:' . PHP_EOL . + 'curl -s http://getcomposer.org/installer | php' . PHP_EOL . + 'php composer.phar install' . PHP_EOL + ); } $QUEUE = getenv('QUEUE'); if(empty($QUEUE)) { - die("Set QUEUE env var containing the list of queues to work.\n"); + die("Set QUEUE env var containing the list of queues to work.\n"); } $REDIS_BACKEND = getenv('REDIS_BACKEND'); $REDIS_BACKEND_DB = getenv('REDIS_BACKEND_DB'); if(!empty($REDIS_BACKEND)) { - if (empty($REDIS_BACKEND_DB)) - Resque::setBackend($REDIS_BACKEND); - else - Resque::setBackend($REDIS_BACKEND, $REDIS_BACKEND_DB); + if (empty($REDIS_BACKEND_DB)) + Resque::setBackend($REDIS_BACKEND); + else + Resque::setBackend($REDIS_BACKEND, $REDIS_BACKEND_DB); } $logLevel = 0; @@ -44,31 +44,33 @@ $LOGGING = getenv('LOGGING'); $VERBOSE = getenv('VERBOSE'); $VVERBOSE = getenv('VVERBOSE'); if(!empty($LOGGING) || !empty($VERBOSE)) { - $logLevel = Resque_Worker::LOG_NORMAL; + $logLevel = Resque_Worker::LOG_NORMAL; } else if(!empty($VVERBOSE)) { - $logLevel = Resque_Worker::LOG_VERBOSE; + $logLevel = Resque_Worker::LOG_VERBOSE; } $APP_INCLUDE = getenv('APP_INCLUDE'); if($APP_INCLUDE) { - if(!file_exists($APP_INCLUDE)) { - die('APP_INCLUDE ('.$APP_INCLUDE.") does not exist.\n"); - } + if(!file_exists($APP_INCLUDE)) { + die('APP_INCLUDE ('.$APP_INCLUDE.") does not exist.\n"); + } - require_once $APP_INCLUDE; + require_once $APP_INCLUDE; } +$BLOCKING = getenv('BLOCKING') !== FALSE; + $interval = 5; $INTERVAL = getenv('INTERVAL'); if(!empty($INTERVAL)) { - $interval = $INTERVAL; + $interval = $INTERVAL; } $count = 1; $COUNT = getenv('COUNT'); if(!empty($COUNT) && $COUNT > 1) { - $count = $COUNT; + $count = $COUNT; } $PREFIX = getenv('PREFIX'); @@ -78,35 +80,35 @@ if(!empty($PREFIX)) { } if($count > 1) { - for($i = 0; $i < $count; ++$i) { - $pid = Resque::fork(); - if($pid == -1) { - die("Could not fork worker ".$i."\n"); - } - // Child, start the worker - else if(!$pid) { - $queues = explode(',', $QUEUE); - $worker = new Resque_Worker($queues); - $worker->logLevel = $logLevel; - fwrite(STDOUT, '*** Starting worker '.$worker."\n"); - $worker->work($interval); - break; - } - } + for($i = 0; $i < $count; ++$i) { + $pid = Resque::fork(); + if($pid == -1) { + die("Could not fork worker ".$i."\n"); + } + // Child, start the worker + else if(!$pid) { + $queues = explode(',', $QUEUE); + $worker = new Resque_Worker($queues); + $worker->logLevel = $logLevel; + fwrite(STDOUT, '*** Starting worker '.$worker."\n"); + $worker->work($interval, $BLOCKING); + break; + } + } } // Start a single worker else { - $queues = explode(',', $QUEUE); - $worker = new Resque_Worker($queues); - $worker->logLevel = $logLevel; + $queues = explode(',', $QUEUE); + $worker = new Resque_Worker($queues); + $worker->logLevel = $logLevel; - $PIDFILE = getenv('PIDFILE'); - if ($PIDFILE) { - file_put_contents($PIDFILE, getmypid()) or - die('Could not write PID information to ' . $PIDFILE); - } + $PIDFILE = getenv('PIDFILE'); + if ($PIDFILE) { + file_put_contents($PIDFILE, getmypid()) or + die('Could not write PID information to ' . $PIDFILE); + } - fwrite(STDOUT, '*** Starting worker '.$worker."\n"); - $worker->work($interval); + fwrite(STDOUT, '*** Starting worker '.$worker."\n"); + $worker->work($interval, $BLOCKING); } -?> +?> \ No newline at end of file diff --git a/bin/resque.php b/bin/resque.php deleted file mode 100644 index 3fc788f5..00000000 --- a/bin/resque.php +++ /dev/null @@ -1,105 +0,0 @@ - 1) { - $count = $COUNT; -} - -if($count > 1) { - for($i = 0; $i < $count; ++$i) { - $pid = Resque::fork(); - if($pid == -1) { - die("Could not fork worker ".$i."\n"); - } - // Child, start the worker - else if(!$pid) { - $queues = explode(',', $QUEUE); - $worker = new Resque_Worker($queues); - $worker->logLevel = $logLevel; - fwrite(STDOUT, '*** Starting worker '.$worker."\n"); - $worker->work($interval, $BLOCKING); - break; - } - } -} -// Start a single worker -else { - $queues = explode(',', $QUEUE); - $worker = new Resque_Worker($queues); - $worker->logLevel = $logLevel; - - $PIDFILE = getenv('PIDFILE'); - if ($PIDFILE) { - file_put_contents($PIDFILE, getmypid()) or - die('Could not write PID information to ' . $PIDFILE); - } - - fwrite(STDOUT, '*** Starting worker '.$worker."\n"); - $worker->work($interval, $BLOCKING); -} \ No newline at end of file From a0eaac47094de2bd0f451fa3e3a3fa2caa3c9c55 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Mon, 3 Jun 2013 18:10:14 +0200 Subject: [PATCH 104/194] Updated credis dependency to 1.2.* (fixes a bug in blpop) --- composer.json | 2 +- composer.lock | 31 +++++++++++++++++-------------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/composer.json b/composer.json index d94ef1a6..6ea9b0d6 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "php": ">=5.3.0", "ext-pcntl": "*", - "colinmollenhour/credis": "dev-master" + "colinmollenhour/credis": "1.2.*" }, "suggest": { "ext-proctitle": "Allows php-resque to rename the title of UNIX processes to show the status of a worker.", diff --git a/composer.lock b/composer.lock index 760d4cf5..71405359 100644 --- a/composer.lock +++ b/composer.lock @@ -1,18 +1,22 @@ { - "hash": "d37909ad0ffc11ed4d1e67dcaabe00b2", + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" + ], + "hash": "1f551c3cdade1b7ff7d9e32a44eeb3dc", "packages": [ { "name": "colinmollenhour/credis", - "version": "dev-master", + "version": "1.2", "source": { "type": "git", - "url": "https://github.com/chrisboulton/credis", - "reference": "62c73dd16e08069e3fd8f224cb4a5ddd73db8095" + "url": "https://github.com/colinmollenhour/credis.git", + "reference": "1.2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/chrisboulton/credis/zipball/62c73dd16e08069e3fd8f224cb4a5ddd73db8095", - "reference": "62c73dd16e08069e3fd8f224cb4a5ddd73db8095", + "url": "https://api.github.com/repos/colinmollenhour/credis/zipball/1.2", + "reference": "1.2", "shasum": "" }, "require": { @@ -25,6 +29,7 @@ "Cluster.php" ] }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -36,10 +41,7 @@ ], "description": "Credis is a lightweight interface to the Redis key-value store which wraps the phpredis library when available for better performance.", "homepage": "https://github.com/colinmollenhour/credis", - "support": { - "source": "https://github.com/chrisboulton/credis/tree/master" - }, - "time": "2013-01-12 10:15:31" + "time": "2013-03-19 02:57:04" } ], "packages-dev": [ @@ -449,11 +451,12 @@ ], "minimum-stability": "stable", - "stability-flags": { - "colinmollenhour/credis": 20 - }, + "stability-flags": [ + + ], "platform": { - "php": ">=5.3.0" + "php": ">=5.3.0", + "ext-pcntl": "*" }, "platform-dev": [ From 7aa9abdb2e6da5d7f84bd6fc7488e97c68c48351 Mon Sep 17 00:00:00 2001 From: Rockstar04 Date: Tue, 25 Jun 2013 08:56:28 -0700 Subject: [PATCH 105/194] Added PSR3 to composer dependencies --- composer.json | 3 +- composer.lock | 77 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 61 insertions(+), 19 deletions(-) diff --git a/composer.json b/composer.json index 6ea9b0d6..fb868bc6 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,8 @@ "require": { "php": ">=5.3.0", "ext-pcntl": "*", - "colinmollenhour/credis": "1.2.*" + "colinmollenhour/credis": "1.2.*", + "psr/log": "1.0.0" }, "suggest": { "ext-proctitle": "Allows php-resque to rename the title of UNIX processes to show the status of a worker.", diff --git a/composer.lock b/composer.lock index 71405359..1a84e922 100644 --- a/composer.lock +++ b/composer.lock @@ -3,7 +3,7 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "1f551c3cdade1b7ff7d9e32a44eeb3dc", + "hash": "646010a06695709794f1bc38392e392f", "packages": [ { "name": "colinmollenhour/credis", @@ -42,21 +42,59 @@ "description": "Credis is a lightweight interface to the Redis key-value store which wraps the phpredis library when available for better performance.", "homepage": "https://github.com/colinmollenhour/credis", "time": "2013-03-19 02:57:04" + }, + { + "name": "psr/log", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log", + "reference": "1.0.0" + }, + "dist": { + "type": "zip", + "url": "https://github.com/php-fig/log/archive/1.0.0.zip", + "reference": "1.0.0", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2012-12-21 11:40:51" } ], "packages-dev": [ { "name": "phpunit/php-code-coverage", - "version": "1.2.9", + "version": "1.2.11", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "1.2.9" + "reference": "1.2.11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.9", - "reference": "1.2.9", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.11", + "reference": "1.2.11", "shasum": "" }, "require": { @@ -65,6 +103,9 @@ "phpunit/php-text-template": ">=1.1.1@stable", "phpunit/php-token-stream": ">=1.1.3@stable" }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, "suggest": { "ext-dom": "*", "ext-xdebug": ">=2.0.5" @@ -96,7 +137,7 @@ "testing", "xunit" ], - "time": "2013-02-26 18:55:56" + "time": "2013-05-23 18:23:24" }, { "name": "phpunit/php-file-iterator", @@ -278,16 +319,16 @@ }, { "name": "phpunit/phpunit", - "version": "3.7.18", + "version": "3.7.21", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "3.7.18" + "reference": "3.7.21" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.18", - "reference": "3.7.18", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.21", + "reference": "3.7.21", "shasum": "" }, "require": { @@ -301,7 +342,7 @@ "phpunit/php-text-template": ">=1.1.1", "phpunit/php-timer": ">=1.0.2,<1.1.0", "phpunit/phpunit-mock-objects": ">=1.2.0,<1.3.0", - "symfony/yaml": ">=2.2.0" + "symfony/yaml": ">=2.0,<3.0" }, "require-dev": { "pear-pear/pear": "1.9.4" @@ -348,7 +389,7 @@ "testing", "xunit" ], - "time": "2013-03-07 21:45:39" + "time": "2013-05-23 18:54:29" }, { "name": "phpunit/phpunit-mock-objects", @@ -401,17 +442,17 @@ }, { "name": "symfony/yaml", - "version": "v2.2.0", + "version": "v2.3.1", "target-dir": "Symfony/Component/Yaml", "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "v2.2.0-RC3" + "reference": "v2.3.1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.2.0-RC3", - "reference": "v2.2.0-RC3", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.3.1", + "reference": "v2.3.1", "shasum": "" }, "require": { @@ -420,7 +461,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -444,7 +485,7 @@ ], "description": "Symfony Yaml Component", "homepage": "http://symfony.com/", - "time": "2013-01-27 16:49:19" + "time": "2013-05-10 18:12:13" } ], "aliases": [ From 726e58a297a22aeb30607f97b01343993696a134 Mon Sep 17 00:00:00 2001 From: Rockstar04 Date: Tue, 25 Jun 2013 10:06:37 -0700 Subject: [PATCH 106/194] Added basic logging class for a fallback Corrected unit tests for new code Add partial unit coverage for logging class Add newline to logTest file --- bin/resque | 21 ++++---- lib/Resque/Log.php | 62 ++++++++++++++++++++++ lib/Resque/Worker.php | 80 ++++++++++++----------------- test/Resque/Tests/EventTest.php | 1 + test/Resque/Tests/JobStatusTest.php | 1 + test/Resque/Tests/JobTest.php | 1 + test/Resque/Tests/LogTest.php | 31 +++++++++++ test/Resque/Tests/WorkerTest.php | 20 ++++++++ 8 files changed, 161 insertions(+), 56 deletions(-) create mode 100644 lib/Resque/Log.php create mode 100644 test/Resque/Tests/LogTest.php diff --git a/bin/resque b/bin/resque index f0f14294..890c5298 100755 --- a/bin/resque +++ b/bin/resque @@ -39,17 +39,19 @@ if(!empty($REDIS_BACKEND)) { Resque::setBackend($REDIS_BACKEND, $REDIS_BACKEND_DB); } -$logLevel = 0; +$logLevel = false; $LOGGING = getenv('LOGGING'); $VERBOSE = getenv('VERBOSE'); $VVERBOSE = getenv('VVERBOSE'); if(!empty($LOGGING) || !empty($VERBOSE)) { - $logLevel = Resque_Worker::LOG_NORMAL; + $logLevel = true; } else if(!empty($VVERBOSE)) { - $logLevel = Resque_Worker::LOG_VERBOSE; + $logLevel = true; } +$logger = new Resque_Log($logLevel); + $APP_INCLUDE = getenv('APP_INCLUDE'); if($APP_INCLUDE) { if(!file_exists($APP_INCLUDE)) { @@ -75,7 +77,7 @@ if(!empty($COUNT) && $COUNT > 1) { $PREFIX = getenv('PREFIX'); if(!empty($PREFIX)) { - fwrite(STDOUT, '*** Prefix set to '.$PREFIX."\n"); + $logger->log(Psr\Log\LogLevel::INFO, 'Prefix set to {prefix}', array('prefix' => $PREFIX)); Resque_Redis::prefix($PREFIX); } @@ -83,14 +85,15 @@ if($count > 1) { for($i = 0; $i < $count; ++$i) { $pid = Resque::fork(); if($pid == -1) { - die("Could not fork worker ".$i."\n"); + $logger->log(Psr\Log\LogLevel::EMERGENCY, 'Could not fork worker {count}', array('count' => $i)); + die(); } // Child, start the worker else if(!$pid) { $queues = explode(',', $QUEUE); $worker = new Resque_Worker($queues); - $worker->logLevel = $logLevel; - fwrite(STDOUT, '*** Starting worker '.$worker."\n"); + $worker->setLogger(new Resque_Log($logLevel)); + $logger->log(Psr\Log\LogLevel::NOTICE, 'Starting worker {worker}', array('worker' => $worker)); $worker->work($interval, $BLOCKING); break; } @@ -100,7 +103,7 @@ if($count > 1) { else { $queues = explode(',', $QUEUE); $worker = new Resque_Worker($queues); - $worker->logLevel = $logLevel; + $worker->setLogger(new Resque_Log($logLevel)); $PIDFILE = getenv('PIDFILE'); if ($PIDFILE) { @@ -108,7 +111,7 @@ else { die('Could not write PID information to ' . $PIDFILE); } - fwrite(STDOUT, '*** Starting worker '.$worker."\n"); + $logger->log(Psr\Log\LogLevel::NOTICE, 'Starting worker {worker}', array('worker' => $worker)); $worker->work($interval, $BLOCKING); } ?> \ No newline at end of file diff --git a/lib/Resque/Log.php b/lib/Resque/Log.php new file mode 100644 index 00000000..ce279cc6 --- /dev/null +++ b/lib/Resque/Log.php @@ -0,0 +1,62 @@ + + * @license http://www.opensource.org/licenses/mit-license.php + */ +class Resque_Log extends Psr\Log\AbstractLogger +{ + public $verbose; + + public function __construct($verbose = false) { + $this->verbose = $verbose; + } + + /** + * Logs with an arbitrary level. + * + * @param mixed $level PSR-3 log level constant, or equivalent string + * @param string $message Message to log, may contain a { placeholder } + * @param array $context Variables to replace { placeholder } + * @return null + */ + public function log($level, $message, array $context = array()) + { + if ($this->verbose) { + fwrite( + STDOUT, + '[' . $level . '] [' . strftime('%T %Y-%m-%d') . '] ' . $this->interpolate($message, $context) . PHP_EOL + ); + return; + } + + if (!($level === Psr\Log\LogLevel::INFO || $level === Psr\Log\LogLevel::DEBUG)) { + fwrite( + STDOUT, + '[' . $level . '] ' . $this->interpolate($message, $context) . PHP_EOL + ); + } + } + + /** + * Fill placeholders with the provided context + * @author Jordi Boggiano j.boggiano@seld.be + * + * @param string $message Message to be logged + * @param array $context Array of variables to use in message + * @return string + */ + public function interpolate($message, array $context = array()) + { + // build a replacement array with braces around the context keys + $replace = array(); + foreach ($context as $key => $val) { + $replace['{' . $key . '}'] = $val; + } + + // interpolate replacement values into the message and return + return strtr($message, $replace); + } +} diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 870d4c8c..28161c96 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -9,14 +9,10 @@ */ class Resque_Worker { - const LOG_NONE = 0; - const LOG_NORMAL = 1; - const LOG_VERBOSE = 2; - /** - * @var int Current log level of this worker. - */ - public $logLevel = 0; + * @var LoggerInterface Logging object that impliments the PSR-3 LoggerInterface + */ + public $logger; /** * @var array Array of all associated queues for this worker. @@ -161,7 +157,7 @@ public function work($interval = Resque::DEFAULT_INTERVAL, $blocking = false) $job = false; if(!$this->paused) { if($blocking === true) { - $this->log('Starting blocking with timeout of ' . $interval, self::LOG_VERBOSE); + $this->logger->log(Psr\Log\LogLevel::INFO, 'Starting blocking with timeout of {interval}', array('interval' => $interval)); $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with blocking timeout ' . $interval); } else { $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); @@ -179,7 +175,7 @@ public function work($interval = Resque::DEFAULT_INTERVAL, $blocking = false) if($blocking === false) { // If no job was found, we sleep for $interval before continuing and checking again - $this->log('Sleeping for ' . $interval, self::LOG_VERBOSE); + $this->logger->log(Psr\Log\LogLevel::INFO, 'Sleeping for {interval}', array('interval' => $interval)); if($this->paused) { $this->updateProcLine('Paused'); } @@ -193,7 +189,7 @@ public function work($interval = Resque::DEFAULT_INTERVAL, $blocking = false) continue; } - $this->log('got ' . $job); + $this->logger->log(Psr\Log\LogLevel::NOTICE, 'Starting work on {job}', array('job' => $job)); Resque_Event::trigger('beforeFork', $job); $this->workingOn($job); @@ -203,7 +199,7 @@ public function work($interval = Resque::DEFAULT_INTERVAL, $blocking = false) if ($this->child === 0 || $this->child === false) { $status = 'Processing ' . $job->queue . ' since ' . strftime('%F %T'); $this->updateProcLine($status); - $this->log($status, self::LOG_VERBOSE); + $this->logger->log(Psr\Log\LogLevel::INFO, $status); $this->perform($job); if ($this->child === 0) { exit(0); @@ -214,7 +210,7 @@ public function work($interval = Resque::DEFAULT_INTERVAL, $blocking = false) // Parent process, sit and wait $status = 'Forked ' . $this->child . ' at ' . strftime('%F %T'); $this->updateProcLine($status); - $this->log($status, self::LOG_VERBOSE); + $this->logger->log(Psr\Log\LogLevel::INFO, $status); // Wait until the child process finishes before continuing pcntl_wait($status); @@ -245,13 +241,13 @@ public function perform(Resque_Job $job) $job->perform(); } catch(Exception $e) { - $this->log($job . ' failed: ' . $e->getMessage()); + $this->logger->log(Psr\Log\LogLevel::CRITICAL, '{job} has failed {stack}', array('job' => $job, 'stack' => $e->getMessage())); $job->fail($e); return; } $job->updateStatus(Resque_Job_Status::STATUS_COMPLETE); - $this->log('done ' . $job); + $this->logger->log(Psr\Log\LogLevel::NOTICE, '{job} has finished', array('job' => $job)); } /** @@ -269,15 +265,15 @@ public function reserve($blocking = false, $timeout = null) if($blocking === true) { $job = Resque_Job::reserveBlocking($queues, $timeout); if($job) { - $this->log('Found job on ' . $job->queue, self::LOG_VERBOSE); + $this->logger->log(Psr\Log\LogLevel::INFO, 'Found job on {queue}', array('queue' => $job->queue)); return $job; } } else { foreach($queues as $queue) { - $this->log('Checking ' . $queue, self::LOG_VERBOSE); + $this->logger->log(Psr\Log\LogLevel::INFO, 'Checking {queue} for jobs', array('queue' => $queue)); $job = Resque_Job::reserve($queue); if($job) { - $this->log('Found job on ' . $queue, self::LOG_VERBOSE); + $this->logger->log(Psr\Log\LogLevel::INFO, 'Found job on {queue}', array('queue' => $job->queue)); return $job; } } @@ -355,7 +351,7 @@ private function registerSigHandlers() pcntl_signal(SIGUSR2, array($this, 'pauseProcessing')); pcntl_signal(SIGCONT, array($this, 'unPauseProcessing')); pcntl_signal(SIGPIPE, array($this, 'reestablishRedisConnection')); - $this->log('Registered signals', self::LOG_VERBOSE); + $this->logger->log(Psr\Log\LogLevel::DEBUG, 'Registered signals'); } /** @@ -363,7 +359,7 @@ private function registerSigHandlers() */ public function pauseProcessing() { - $this->log('USR2 received; pausing job processing'); + $this->logger->log(Psr\Log\LogLevel::NOTICE, 'USR2 received; pausing job processing'); $this->paused = true; } @@ -373,7 +369,7 @@ public function pauseProcessing() */ public function unPauseProcessing() { - $this->log('CONT received; resuming job processing'); + $this->logger->log(Psr\Log\LogLevel::NOTICE, 'CONT received; resuming job processing'); $this->paused = false; } @@ -383,7 +379,7 @@ public function unPauseProcessing() */ public function reestablishRedisConnection() { - $this->log('SIGPIPE received; attempting to reconnect'); + $this->logger->log(Psr\Log\LogLevel::NOTICE, 'SIGPIPE received; attempting to reconnect'); Resque::redis()->establishConnection(); } @@ -394,7 +390,7 @@ public function reestablishRedisConnection() public function shutdown() { $this->shutdown = true; - $this->log('Exiting...'); + $this->logger->log(Psr\Log\LogLevel::NOTICE, 'Shutting down'); } /** @@ -414,18 +410,18 @@ public function shutdownNow() public function killChild() { if(!$this->child) { - $this->log('No child to kill.', self::LOG_VERBOSE); + $this->logger->log(Psr\Log\LogLevel::DEBUG, 'No child to kill.'); return; } - $this->log('Killing child at ' . $this->child, self::LOG_VERBOSE); + $this->logger->log(Psr\Log\LogLevel::INFO, 'Killing child at {child}', array('child' => $this->child)); if(exec('ps -o pid,state -p ' . $this->child, $output, $returnCode) && $returnCode != 1) { - $this->log('Killing child at ' . $this->child, self::LOG_VERBOSE); + $this->logger->log(Psr\Log\LogLevel::DEBUG, 'Child {child} found, killing.', array('child' => $this->child)); posix_kill($this->child, SIGKILL); $this->child = null; } else { - $this->log('Child ' . $this->child . ' not found, restarting.', self::LOG_VERBOSE); + $this->logger->log(Psr\Log\LogLevel::INFO, 'Child {child} not found, restarting.', array('child' => $this->child)); $this->shutdown(); } } @@ -448,7 +444,7 @@ public function pruneDeadWorkers() if($host != $this->hostname || in_array($pid, $workerPids) || $pid == getmypid()) { continue; } - $this->log('Pruning dead worker: ' . (string)$worker, self::LOG_VERBOSE); + $this->logger->log(Psr\Log\LogLevel::INFO, 'Pruning dead worker: {worker}', array('worker' => (string)$worker)); $worker->unregisterWorker(); } } @@ -536,26 +532,6 @@ public function __toString() return $this->id; } - /** - * Output a given log message to STDOUT. - * - * @param string $message Message to output. - * @param int $logLevel The logging level to capture - */ - public function log($message, $logLevel = self::LOG_NORMAL) - { - if ($logLevel > $this->logLevel) { - return; - } - - if ($this->logLevel == self::LOG_NORMAL) { - fwrite(STDOUT, "*** " . $message . "\n"); - return; - } - - fwrite(STDOUT, "** [" . strftime('%T %Y-%m-%d') . "] " . $message . "\n"); - } - /** * Return an object describing the job this worker is currently working on. * @@ -582,5 +558,15 @@ public function getStat($stat) { return Resque_Stat::get($stat . ':' . $this); } + + /** + * Inject the logging object into the worker + * + * @param Psr\Log\LoggerInterface $logger + */ + public function setLogger(Psr\Log\LoggerInterface $logger) + { + $this->logger = $logger; + } } ?> diff --git a/test/Resque/Tests/EventTest.php b/test/Resque/Tests/EventTest.php index 880a323e..894fd7a9 100644 --- a/test/Resque/Tests/EventTest.php +++ b/test/Resque/Tests/EventTest.php @@ -16,6 +16,7 @@ public function setUp() // Register a worker to test with $this->worker = new Resque_Worker('jobs'); + $this->worker->setLogger(new Resque_Log()); $this->worker->registerWorker(); } diff --git a/test/Resque/Tests/JobStatusTest.php b/test/Resque/Tests/JobStatusTest.php index 68a25ff4..d751c37f 100644 --- a/test/Resque/Tests/JobStatusTest.php +++ b/test/Resque/Tests/JobStatusTest.php @@ -19,6 +19,7 @@ public function setUp() // Register a worker to test with $this->worker = new Resque_Worker('jobs'); + $this->worker->setLogger(new Resque_Log()); } public function testJobStatusCanBeTracked() diff --git a/test/Resque/Tests/JobTest.php b/test/Resque/Tests/JobTest.php index 688c2654..0c096966 100644 --- a/test/Resque/Tests/JobTest.php +++ b/test/Resque/Tests/JobTest.php @@ -17,6 +17,7 @@ public function setUp() // Register a worker to test with $this->worker = new Resque_Worker('jobs'); + $this->worker->setLogger(new Resque_Log()); $this->worker->registerWorker(); } diff --git a/test/Resque/Tests/LogTest.php b/test/Resque/Tests/LogTest.php new file mode 100644 index 00000000..db97b160 --- /dev/null +++ b/test/Resque/Tests/LogTest.php @@ -0,0 +1,31 @@ + + * @license http://www.opensource.org/licenses/mit-license.php + */ +class Resque_Tests_LogTest extends Resque_Tests_TestCase +{ + public function testLogInterpolate() + { + $logger = new Resque_Log(); + $actual = $logger->interpolate('string {replace}', array('replace' => 'value')); + $expected = 'string value'; + + $this->assertEquals($expected, $actual); + } + + public function testLogInterpolateMutiple() + { + $logger = new Resque_Log(); + $actual = $logger->interpolate( + 'string {replace1} {replace2}', + array('replace1' => 'value1', 'replace2' => 'value2') + ); + $expected = 'string value1 value2'; + + $this->assertEquals($expected, $actual); + } +} diff --git a/test/Resque/Tests/WorkerTest.php b/test/Resque/Tests/WorkerTest.php index 1ab7dd27..93c0621a 100644 --- a/test/Resque/Tests/WorkerTest.php +++ b/test/Resque/Tests/WorkerTest.php @@ -11,6 +11,7 @@ class Resque_Tests_WorkerTest extends Resque_Tests_TestCase public function testWorkerRegistersInList() { $worker = new Resque_Worker('*'); + $worker->setLogger(new Resque_Log()); $worker->registerWorker(); // Make sure the worker is in the list @@ -23,6 +24,7 @@ public function testGetAllWorkers() // Register a few workers for($i = 0; $i < $num; ++$i) { $worker = new Resque_Worker('queue_' . $i); + $worker->setLogger(new Resque_Log()); $worker->registerWorker(); } @@ -33,6 +35,7 @@ public function testGetAllWorkers() public function testGetWorkerById() { $worker = new Resque_Worker('*'); + $worker->setLogger(new Resque_Log()); $worker->registerWorker(); $newWorker = Resque_Worker::find((string)$worker); @@ -47,6 +50,7 @@ public function testInvalidWorkerDoesNotExist() public function testWorkerCanUnregister() { $worker = new Resque_Worker('*'); + $worker->setLogger(new Resque_Log()); $worker->registerWorker(); $worker->unregisterWorker(); @@ -58,6 +62,7 @@ public function testWorkerCanUnregister() public function testPausedWorkerDoesNotPickUpJobs() { $worker = new Resque_Worker('*'); + $worker->setLogger(new Resque_Log()); $worker->pauseProcessing(); Resque::enqueue('jobs', 'Test_Job'); $worker->work(0); @@ -68,6 +73,7 @@ public function testPausedWorkerDoesNotPickUpJobs() public function testResumedWorkerPicksUpJobs() { $worker = new Resque_Worker('*'); + $worker->setLogger(new Resque_Log()); $worker->pauseProcessing(); Resque::enqueue('jobs', 'Test_Job'); $worker->work(0); @@ -83,6 +89,7 @@ public function testWorkerCanWorkOverMultipleQueues() 'queue1', 'queue2' )); + $worker->setLogger(new Resque_Log()); $worker->registerWorker(); Resque::enqueue('queue1', 'Test_Job_1'); Resque::enqueue('queue2', 'Test_Job_2'); @@ -101,6 +108,7 @@ public function testWorkerWorksQueuesInSpecifiedOrder() 'medium', 'low' )); + $worker->setLogger(new Resque_Log()); $worker->registerWorker(); // Queue the jobs in a different order @@ -122,6 +130,7 @@ public function testWorkerWorksQueuesInSpecifiedOrder() public function testWildcardQueueWorkerWorksAllQueues() { $worker = new Resque_Worker('*'); + $worker->setLogger(new Resque_Log()); $worker->registerWorker(); Resque::enqueue('queue1', 'Test_Job_1'); @@ -137,6 +146,7 @@ public function testWildcardQueueWorkerWorksAllQueues() public function testWorkerDoesNotWorkOnUnknownQueues() { $worker = new Resque_Worker('queue1'); + $worker->setLogger(new Resque_Log()); $worker->registerWorker(); Resque::enqueue('queue2', 'Test_Job'); @@ -147,6 +157,7 @@ public function testWorkerClearsItsStatusWhenNotWorking() { Resque::enqueue('jobs', 'Test_Job'); $worker = new Resque_Worker('jobs'); + $worker->setLogger(new Resque_Log()); $job = $worker->reserve(); $worker->workingOn($job); $worker->doneWorking(); @@ -156,6 +167,7 @@ public function testWorkerClearsItsStatusWhenNotWorking() public function testWorkerRecordsWhatItIsWorkingOn() { $worker = new Resque_Worker('jobs'); + $worker->setLogger(new Resque_Log()); $worker->registerWorker(); $payload = array( @@ -178,6 +190,7 @@ public function testWorkerErasesItsStatsWhenShutdown() Resque::enqueue('jobs', 'Invalid_Job'); $worker = new Resque_Worker('jobs'); + $worker->setLogger(new Resque_Log()); $worker->work(0); $worker->work(0); @@ -189,15 +202,18 @@ public function testWorkerCleansUpDeadWorkersOnStartup() { // Register a good worker $goodWorker = new Resque_Worker('jobs'); + $goodWorker->setLogger(new Resque_Log()); $goodWorker->registerWorker(); $workerId = explode(':', $goodWorker); // Register some bad workers $worker = new Resque_Worker('jobs'); + $worker->setLogger(new Resque_Log()); $worker->setId($workerId[0].':1:jobs'); $worker->registerWorker(); $worker = new Resque_Worker(array('high', 'low')); + $worker->setLogger(new Resque_Log()); $worker->setId($workerId[0].':2:high,low'); $worker->registerWorker(); @@ -213,12 +229,14 @@ public function testDeadWorkerCleanUpDoesNotCleanUnknownWorkers() { // Register a bad worker on this machine $worker = new Resque_Worker('jobs'); + $worker->setLogger(new Resque_Log()); $workerId = explode(':', $worker); $worker->setId($workerId[0].':1:jobs'); $worker->registerWorker(); // Register some other false workers $worker = new Resque_Worker('jobs'); + $worker->setLogger(new Resque_Log()); $worker->setId('my.other.host:1:jobs'); $worker->registerWorker(); @@ -235,6 +253,7 @@ public function testDeadWorkerCleanUpDoesNotCleanUnknownWorkers() public function testWorkerFailsUncompletedJobsOnExit() { $worker = new Resque_Worker('jobs'); + $worker->setLogger(new Resque_Log()); $worker->registerWorker(); $payload = array( @@ -251,6 +270,7 @@ public function testWorkerFailsUncompletedJobsOnExit() public function testBlockingListPop() { $worker = new Resque_Worker('jobs'); + $worker->setLogger(new Resque_Log()); $worker->registerWorker(); Resque::enqueue('jobs', 'Test_Job_1'); From 5cef885a0602d7c09f53e81baeb05529e6676e90 Mon Sep 17 00:00:00 2001 From: Rockstar04 Date: Tue, 25 Jun 2013 12:10:08 -0700 Subject: [PATCH 107/194] Look for a var in the bin/resque script to allow override --- bin/resque | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/bin/resque b/bin/resque index 890c5298..b9a10cf6 100755 --- a/bin/resque +++ b/bin/resque @@ -50,8 +50,6 @@ else if(!empty($VVERBOSE)) { $logLevel = true; } -$logger = new Resque_Log($logLevel); - $APP_INCLUDE = getenv('APP_INCLUDE'); if($APP_INCLUDE) { if(!file_exists($APP_INCLUDE)) { @@ -61,6 +59,12 @@ if($APP_INCLUDE) { require_once $APP_INCLUDE; } +// See if the APP_INCLUDE containes a logger object, +// If none exists, fallback to internal logger +if (!isset($logger) && !is_object($logger)) { + $logger = new Resque_Log($logLevel); +} + $BLOCKING = getenv('BLOCKING') !== FALSE; $interval = 5; @@ -92,7 +96,7 @@ if($count > 1) { else if(!$pid) { $queues = explode(',', $QUEUE); $worker = new Resque_Worker($queues); - $worker->setLogger(new Resque_Log($logLevel)); + $worker->setLogger($logger); $logger->log(Psr\Log\LogLevel::NOTICE, 'Starting worker {worker}', array('worker' => $worker)); $worker->work($interval, $BLOCKING); break; @@ -103,7 +107,7 @@ if($count > 1) { else { $queues = explode(',', $QUEUE); $worker = new Resque_Worker($queues); - $worker->setLogger(new Resque_Log($logLevel)); + $worker->setLogger($logger); $PIDFILE = getenv('PIDFILE'); if ($PIDFILE) { From 88f494e7ce1a1f9e6ad6397f67fdd8cf52eeb31c Mon Sep 17 00:00:00 2001 From: Arthur Cinader Date: Wed, 3 Jul 2013 21:12:10 -0700 Subject: [PATCH 108/194] Update README.md Remove redundant use of "include" in documentation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3d75992e..fc1047af 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,7 @@ Workers work in the exact same way as the Ruby workers. For complete documentation on workers, see the original documentation. A basic "up-and-running" `bin/resque` file is included that sets up a -running worker environment is included. (`vendor/bin/resque` when installed +running worker environment. (`vendor/bin/resque` when installed via Composer) The exception to the similarities with the Ruby version of resque is From 25a804d93da848e69f6ac999b84065e57623fdb4 Mon Sep 17 00:00:00 2001 From: Trent Petersen Date: Wed, 10 Jul 2013 10:07:19 -0500 Subject: [PATCH 109/194] Convert indentation in the Worker class.... to . . . . tabs This was painful for me as a PSR 1-2 follower --- lib/Resque/Worker.php | 256 +++++++++++++++++++++--------------------- 1 file changed, 128 insertions(+), 128 deletions(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 28161c96..a6c3985f 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -86,7 +86,7 @@ public static function exists($workerId) */ public static function find($workerId) { - if(!self::exists($workerId) || false === strpos($workerId, ":")) { + if(!self::exists($workerId) || false === strpos($workerId, ":")) { return false; } @@ -148,83 +148,83 @@ public function work($interval = Resque::DEFAULT_INTERVAL, $blocking = false) $this->updateProcLine('Starting'); $this->startup(); - while(true) { - if($this->shutdown) { - break; - } - - // Attempt to find and reserve a job - $job = false; - if(!$this->paused) { - if($blocking === true) { - $this->logger->log(Psr\Log\LogLevel::INFO, 'Starting blocking with timeout of {interval}', array('interval' => $interval)); - $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with blocking timeout ' . $interval); - } else { - $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); - } - - $job = $this->reserve($blocking, $interval); - } - - if(!$job) { - // For an interval of 0, break now - helps with unit testing etc - if($interval == 0) { - break; - } - - if($blocking === false) - { - // If no job was found, we sleep for $interval before continuing and checking again - $this->logger->log(Psr\Log\LogLevel::INFO, 'Sleeping for {interval}', array('interval' => $interval)); - if($this->paused) { - $this->updateProcLine('Paused'); - } - else { - $this->updateProcLine('Waiting for ' . implode(',', $this->queues)); - } - - usleep($interval * 1000000); - } - - continue; - } - - $this->logger->log(Psr\Log\LogLevel::NOTICE, 'Starting work on {job}', array('job' => $job)); - Resque_Event::trigger('beforeFork', $job); - $this->workingOn($job); - - $this->child = Resque::fork(); - - // Forked and we're the child. Run the job. - if ($this->child === 0 || $this->child === false) { - $status = 'Processing ' . $job->queue . ' since ' . strftime('%F %T'); - $this->updateProcLine($status); - $this->logger->log(Psr\Log\LogLevel::INFO, $status); - $this->perform($job); - if ($this->child === 0) { - exit(0); - } - } - - if($this->child > 0) { - // Parent process, sit and wait - $status = 'Forked ' . $this->child . ' at ' . strftime('%F %T'); - $this->updateProcLine($status); - $this->logger->log(Psr\Log\LogLevel::INFO, $status); - - // Wait until the child process finishes before continuing - pcntl_wait($status); - $exitStatus = pcntl_wexitstatus($status); - if($exitStatus !== 0) { - $job->fail(new Resque_Job_DirtyExitException( - 'Job exited with exit code ' . $exitStatus - )); - } - } - - $this->child = null; - $this->doneWorking(); - } + while(true) { + if($this->shutdown) { + break; + } + + // Attempt to find and reserve a job + $job = false; + if(!$this->paused) { + if($blocking === true) { + $this->logger->log(Psr\Log\LogLevel::INFO, 'Starting blocking with timeout of {interval}', array('interval' => $interval)); + $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with blocking timeout ' . $interval); + } else { + $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); + } + + $job = $this->reserve($blocking, $interval); + } + + if(!$job) { + // For an interval of 0, break now - helps with unit testing etc + if($interval == 0) { + break; + } + + if($blocking === false) + { + // If no job was found, we sleep for $interval before continuing and checking again + $this->logger->log(Psr\Log\LogLevel::INFO, 'Sleeping for {interval}', array('interval' => $interval)); + if($this->paused) { + $this->updateProcLine('Paused'); + } + else { + $this->updateProcLine('Waiting for ' . implode(',', $this->queues)); + } + + usleep($interval * 1000000); + } + + continue; + } + + $this->logger->log(Psr\Log\LogLevel::NOTICE, 'Starting work on {job}', array('job' => $job)); + Resque_Event::trigger('beforeFork', $job); + $this->workingOn($job); + + $this->child = Resque::fork(); + + // Forked and we're the child. Run the job. + if ($this->child === 0 || $this->child === false) { + $status = 'Processing ' . $job->queue . ' since ' . strftime('%F %T'); + $this->updateProcLine($status); + $this->logger->log(Psr\Log\LogLevel::INFO, $status); + $this->perform($job); + if ($this->child === 0) { + exit(0); + } + } + + if($this->child > 0) { + // Parent process, sit and wait + $status = 'Forked ' . $this->child . ' at ' . strftime('%F %T'); + $this->updateProcLine($status); + $this->logger->log(Psr\Log\LogLevel::INFO, $status); + + // Wait until the child process finishes before continuing + pcntl_wait($status); + $exitStatus = pcntl_wexitstatus($status); + if($exitStatus !== 0) { + $job->fail(new Resque_Job_DirtyExitException( + 'Job exited with exit code ' . $exitStatus + )); + } + } + + $this->child = null; + $this->doneWorking(); + } $this->unregisterWorker(); } @@ -241,46 +241,46 @@ public function perform(Resque_Job $job) $job->perform(); } catch(Exception $e) { - $this->logger->log(Psr\Log\LogLevel::CRITICAL, '{job} has failed {stack}', array('job' => $job, 'stack' => $e->getMessage())); + $this->logger->log(Psr\Log\LogLevel::CRITICAL, '{job} has failed {stack}', array('job' => $job, 'stack' => $e->getMessage())); $job->fail($e); return; } $job->updateStatus(Resque_Job_Status::STATUS_COMPLETE); - $this->logger->log(Psr\Log\LogLevel::NOTICE, '{job} has finished', array('job' => $job)); + $this->logger->log(Psr\Log\LogLevel::NOTICE, '{job} has finished', array('job' => $job)); } - /** - * @param bool $blocking - * @param int $timeout - * @return object|boolean Instance of Resque_Job if a job is found, false if not. - */ - public function reserve($blocking = false, $timeout = null) - { - $queues = $this->queues(); - if(!is_array($queues)) { - return; - } - - if($blocking === true) { - $job = Resque_Job::reserveBlocking($queues, $timeout); - if($job) { - $this->logger->log(Psr\Log\LogLevel::INFO, 'Found job on {queue}', array('queue' => $job->queue)); - return $job; - } - } else { - foreach($queues as $queue) { - $this->logger->log(Psr\Log\LogLevel::INFO, 'Checking {queue} for jobs', array('queue' => $queue)); - $job = Resque_Job::reserve($queue); - if($job) { - $this->logger->log(Psr\Log\LogLevel::INFO, 'Found job on {queue}', array('queue' => $job->queue)); - return $job; - } - } - } - - return false; - } + /** + * @param bool $blocking + * @param int $timeout + * @return object|boolean Instance of Resque_Job if a job is found, false if not. + */ + public function reserve($blocking = false, $timeout = null) + { + $queues = $this->queues(); + if(!is_array($queues)) { + return; + } + + if($blocking === true) { + $job = Resque_Job::reserveBlocking($queues, $timeout); + if($job) { + $this->logger->log(Psr\Log\LogLevel::INFO, 'Found job on {queue}', array('queue' => $job->queue)); + return $job; + } + } else { + foreach($queues as $queue) { + $this->logger->log(Psr\Log\LogLevel::INFO, 'Checking {queue} for jobs', array('queue' => $queue)); + $job = Resque_Job::reserve($queue); + if($job) { + $this->logger->log(Psr\Log\LogLevel::INFO, 'Found job on {queue}', array('queue' => $job->queue)); + return $job; + } + } + } + + return false; + } /** * Return an array containing all of the queues that this worker should use @@ -351,7 +351,7 @@ private function registerSigHandlers() pcntl_signal(SIGUSR2, array($this, 'pauseProcessing')); pcntl_signal(SIGCONT, array($this, 'unPauseProcessing')); pcntl_signal(SIGPIPE, array($this, 'reestablishRedisConnection')); - $this->logger->log(Psr\Log\LogLevel::DEBUG, 'Registered signals'); + $this->logger->log(Psr\Log\LogLevel::DEBUG, 'Registered signals'); } /** @@ -359,7 +359,7 @@ private function registerSigHandlers() */ public function pauseProcessing() { - $this->logger->log(Psr\Log\LogLevel::NOTICE, 'USR2 received; pausing job processing'); + $this->logger->log(Psr\Log\LogLevel::NOTICE, 'USR2 received; pausing job processing'); $this->paused = true; } @@ -369,7 +369,7 @@ public function pauseProcessing() */ public function unPauseProcessing() { - $this->logger->log(Psr\Log\LogLevel::NOTICE, 'CONT received; resuming job processing'); + $this->logger->log(Psr\Log\LogLevel::NOTICE, 'CONT received; resuming job processing'); $this->paused = false; } @@ -379,7 +379,7 @@ public function unPauseProcessing() */ public function reestablishRedisConnection() { - $this->logger->log(Psr\Log\LogLevel::NOTICE, 'SIGPIPE received; attempting to reconnect'); + $this->logger->log(Psr\Log\LogLevel::NOTICE, 'SIGPIPE received; attempting to reconnect'); Resque::redis()->establishConnection(); } @@ -390,7 +390,7 @@ public function reestablishRedisConnection() public function shutdown() { $this->shutdown = true; - $this->logger->log(Psr\Log\LogLevel::NOTICE, 'Shutting down'); + $this->logger->log(Psr\Log\LogLevel::NOTICE, 'Shutting down'); } /** @@ -410,18 +410,18 @@ public function shutdownNow() public function killChild() { if(!$this->child) { - $this->logger->log(Psr\Log\LogLevel::DEBUG, 'No child to kill.'); + $this->logger->log(Psr\Log\LogLevel::DEBUG, 'No child to kill.'); return; } - $this->logger->log(Psr\Log\LogLevel::INFO, 'Killing child at {child}', array('child' => $this->child)); + $this->logger->log(Psr\Log\LogLevel::INFO, 'Killing child at {child}', array('child' => $this->child)); if(exec('ps -o pid,state -p ' . $this->child, $output, $returnCode) && $returnCode != 1) { - $this->logger->log(Psr\Log\LogLevel::DEBUG, 'Child {child} found, killing.', array('child' => $this->child)); + $this->logger->log(Psr\Log\LogLevel::DEBUG, 'Child {child} found, killing.', array('child' => $this->child)); posix_kill($this->child, SIGKILL); $this->child = null; } else { - $this->logger->log(Psr\Log\LogLevel::INFO, 'Child {child} not found, restarting.', array('child' => $this->child)); + $this->logger->log(Psr\Log\LogLevel::INFO, 'Child {child} not found, restarting.', array('child' => $this->child)); $this->shutdown(); } } @@ -439,14 +439,14 @@ public function pruneDeadWorkers() $workerPids = $this->workerPids(); $workers = self::all(); foreach($workers as $worker) { - if (is_object($worker)) { - list($host, $pid, $queues) = explode(':', (string)$worker, 3); - if($host != $this->hostname || in_array($pid, $workerPids) || $pid == getmypid()) { - continue; - } - $this->logger->log(Psr\Log\LogLevel::INFO, 'Pruning dead worker: {worker}', array('worker' => (string)$worker)); - $worker->unregisterWorker(); - } + if (is_object($worker)) { + list($host, $pid, $queues) = explode(':', (string)$worker, 3); + if($host != $this->hostname || in_array($pid, $workerPids) || $pid == getmypid()) { + continue; + } + $this->logger->log(Psr\Log\LogLevel::INFO, 'Pruning dead worker: {worker}', array('worker' => (string)$worker)); + $worker->unregisterWorker(); + } } } From 271b5849573195d5f6be359038c3d2696b109b1a Mon Sep 17 00:00:00 2001 From: Rajib Ahmed Date: Thu, 18 Jul 2013 09:53:30 +0200 Subject: [PATCH 110/194] Add github style syntax highlights on README file. --- README.md | 135 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 83 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index fc1047af..5feb3445 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,8 @@ If you're not familiar with Composer, please see . 1. Add php-resque to your application's composer.json. +```json + { ... "require": { @@ -58,13 +60,16 @@ If you're not familiar with Composer, please see . }, ... } +``` 2. Run `composer install`. 3. If you haven't already, add the Composer autoload to your project's initialization file. (example) +```sh require 'vendor/autoload.php'; +``` ## Jobs ## @@ -72,6 +77,8 @@ If you're not familiar with Composer, please see . Jobs are queued as follows: +```php + // Required if redis is located elsewhere Resque::setBackend('localhost:6379'); @@ -80,10 +87,14 @@ Jobs are queued as follows: ); Resque::enqueue('default', 'My_Job', $args); +``` + ### Defining Jobs ### Each job should be in it's own class, and include a `perform` method. +```php + class My_Job { public function perform() @@ -93,6 +104,8 @@ Each job should be in it's own class, and include a `perform` method. } } +``` + When the job is run, the class will be instantiated and any arguments will be set as an array on the instantiated object, and are accessible via `$this->args`. @@ -105,23 +118,27 @@ Jobs can also have `setUp` and `tearDown` methods. If a `setUp` method is defined, it will be called before the `perform` method is run. The `tearDown` method if defined, will be called after the job finishes. - class My_Job - { - public function setUp() - { - // ... Set up environment for this job - } - public function perform() - { - // .. Run job - } +```php - public function tearDown() - { - // ... Remove environment for this job - } - } + class My_Job + { + public function setUp() + { + // ... Set up environment for this job + } + + public function perform() + { + // .. Run job + } + + public function tearDown() + { + // ... Remove environment for this job + } + } +``` ### Tracking Job Statuses ### @@ -144,11 +161,11 @@ To fetch the status of a job: Job statuses are defined as constants in the `Resque_Job_Status` class. Valid statuses include: -* `Resque_Job_Status::STATUS_WAITING` - Job is still queued -* `Resque_Job_Status::STATUS_RUNNING` - Job is currently running -* `Resque_Job_Status::STATUS_FAILED` - Job has failed -* `Resque_Job_Status::STATUS_COMPLETE` - Job is complete -* `false` - Failed to fetch the status - is the token valid? + * `Resque_Job_Status::STATUS_WAITING` - Job is still queued + * `Resque_Job_Status::STATUS_RUNNING` - Job is currently running + * `Resque_Job_Status::STATUS_FAILED` - Job has failed + * `Resque_Job_Status::STATUS_COMPLETE` - Job is complete + * `false` - Failed to fetch the status - is the token valid? Statuses are available for up to 24 hours after a job has completed or failed, and are then automatically expired. A status can also @@ -177,7 +194,9 @@ It's your responsibility to tell the worker which file to include to get your application underway. You do so by setting the `APP_INCLUDE` environment variable: +```sh $ QUEUE=file_serve APP_INCLUDE=../application/init.php php bin/resque +``` *Pro tip: Using Composer? More than likely, you don't need to worry about `APP_INCLUDE`, because hopefully Composer is responsible for autoloading @@ -192,8 +211,10 @@ The port supports the same environment variables for logging to STDOUT. Setting `VERBOSE` will print basic debugging information and `VVERBOSE` will print detailed information. +```sh $ VERBOSE QUEUE=file_serve bin/resque $ VVERBOSE QUEUE=file_serve bin/resque +``` ### Priorities and Queue Lists ### @@ -204,7 +225,9 @@ checked in. As per the original example: +```sh $ QUEUE=file_serve,warm_cache bin/resque +``` The `file_serve` queue will always be checked for new jobs on each iteration before the `warm_cache` queue is checked. @@ -214,21 +237,27 @@ iteration before the `warm_cache` queue is checked. All queues are supported in the same manner and processed in alphabetical order: +```sh $ QUEUE=* bin/resque +``` ### Running Multiple Workers ### Multiple workers ca be launched and automatically worked by supplying the `COUNT` environment variable: - $ COUNT=5 bin/resque +```sh + $ COUNT=5 bin/resque +``` ### Custom prefix ### When you have multiple apps using the same Redis database it is better to use a custom prefix to separate the Resque data: - $ PREFIX=my-app-name bin/resque +```sh + $ PREFIX=my-app-name bin/resque +``` ### Forking ### @@ -245,11 +274,11 @@ the job. Signals also work on supported platforms exactly as in the Ruby version of Resque: -* `QUIT` - Wait for child to finish processing then exit -* `TERM` / `INT` - Immediately kill child then exit -* `USR1` - Immediately kill child but don't exit -* `USR2` - Pause worker, no new jobs will be processed -* `CONT` - Resume worker. + * `QUIT` - Wait for child to finish processing then exit + * `TERM` / `INT` - Immediately kill child then exit + * `USR1` - Immediately kill child but don't exit + * `USR2` - Pause worker, no new jobs will be processed + * `CONT` - Resume worker. ### Process Titles/Statuses ### @@ -274,14 +303,16 @@ You listen in on events (as listed below) by registering with `Resque_Event` and supplying a callback that you would like triggered when the event is raised: +```sh Resque_Event::listen('eventName', [callback]); +``` `[callback]` may be anything in PHP that is callable by `call_user_func_array`: -* A string with the name of a function -* An array containing an object and method to call -* An array containing an object and a static method to call -* A closure (PHP 5.3) + * A string with the name of a function + * An array containing an object and method to call + * An array containing an object and a static method to call + * A closure (PHP 5.3) Events may pass arguments (documented below), so your callback should accept these arguments. @@ -358,24 +389,24 @@ Called after a job has been queued using the `Resque::enqueue` method. Arguments ## Contributors ## -* chrisboulton -* thedotedge -* hobodave -* scraton -* KevBurnsJr -* jmathai -* dceballos -* patrickbajao -* andrewjshults -* warezthebeef -* d11wtq -* hlegius -* salimane -* humancopy -* pedroarnal -* chaitanyakuber -* maetl -* Matt Heath -* jjfrey -* scragg0x -* ruudk + * chrisboulton + * thedotedge + * hobodave + * scraton + * KevBurnsJr + * jmathai + * dceballos + * patrickbajao + * andrewjshults + * warezthebeef + * d11wtq + * hlegius + * salimane + * humancopy + * pedroarnal + * chaitanyakuber + * maetl + * Matt Heath + * jjfrey + * scragg0x + * ruudk From 2d4458fbed8ef43c60ff8338e489dfc1a9413669 Mon Sep 17 00:00:00 2001 From: Rajib Ahmed Date: Thu, 18 Jul 2013 09:57:53 +0200 Subject: [PATCH 111/194] Add fix to syntax highlights. --- README.md | 74 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 5feb3445..ae9a3554 100644 --- a/README.md +++ b/README.md @@ -150,22 +150,26 @@ To track the status of a job, pass `true` as the fourth argument to `Resque::enqueue`. A token used for tracking the job status will be returned: +```php $token = Resque::enqueue('default', 'My_Job', $args, true); echo $token; +``` To fetch the status of a job: +```php $status = new Resque_Job_Status($token); echo $status->get(); // Outputs the status +``` Job statuses are defined as constants in the `Resque_Job_Status` class. Valid statuses include: - * `Resque_Job_Status::STATUS_WAITING` - Job is still queued - * `Resque_Job_Status::STATUS_RUNNING` - Job is currently running - * `Resque_Job_Status::STATUS_FAILED` - Job has failed - * `Resque_Job_Status::STATUS_COMPLETE` - Job is complete - * `false` - Failed to fetch the status - is the token valid? +* `Resque_Job_Status::STATUS_WAITING` - Job is still queued +* `Resque_Job_Status::STATUS_RUNNING` - Job is currently running +* `Resque_Job_Status::STATUS_FAILED` - Job has failed +* `Resque_Job_Status::STATUS_COMPLETE` - Job is complete +* `false` - Failed to fetch the status - is the token valid? Statuses are available for up to 24 hours after a job has completed or failed, and are then automatically expired. A status can also @@ -274,11 +278,11 @@ the job. Signals also work on supported platforms exactly as in the Ruby version of Resque: - * `QUIT` - Wait for child to finish processing then exit - * `TERM` / `INT` - Immediately kill child then exit - * `USR1` - Immediately kill child but don't exit - * `USR2` - Pause worker, no new jobs will be processed - * `CONT` - Resume worker. +* `QUIT` - Wait for child to finish processing then exit +* `TERM` / `INT` - Immediately kill child then exit +* `USR1` - Immediately kill child but don't exit +* `USR2` - Pause worker, no new jobs will be processed +* `CONT` - Resume worker. ### Process Titles/Statuses ### @@ -309,10 +313,10 @@ raised: `[callback]` may be anything in PHP that is callable by `call_user_func_array`: - * A string with the name of a function - * An array containing an object and method to call - * An array containing an object and a static method to call - * A closure (PHP 5.3) +* A string with the name of a function +* An array containing an object and method to call +* An array containing an object and a static method to call +* A closure (PHP 5.3) Events may pass arguments (documented below), so your callback should accept these arguments. @@ -389,24 +393,24 @@ Called after a job has been queued using the `Resque::enqueue` method. Arguments ## Contributors ## - * chrisboulton - * thedotedge - * hobodave - * scraton - * KevBurnsJr - * jmathai - * dceballos - * patrickbajao - * andrewjshults - * warezthebeef - * d11wtq - * hlegius - * salimane - * humancopy - * pedroarnal - * chaitanyakuber - * maetl - * Matt Heath - * jjfrey - * scragg0x - * ruudk +* chrisboulton +* thedotedge +* hobodave +* scraton +* KevBurnsJr +* jmathai +* dceballos +* patrickbajao +* andrewjshults +* warezthebeef +* d11wtq +* hlegius +* salimane +* humancopy +* pedroarnal +* chaitanyakuber +* maetl +* Matt Heath +* jjfrey +* scragg0x +* ruudk From 14989b0e9e380ccfd40e799ac0e291fe33fe38ff Mon Sep 17 00:00:00 2001 From: Rajib Ahmed Date: Thu, 18 Jul 2013 11:51:02 +0200 Subject: [PATCH 112/194] Remove spaces from README code samples. --- README.md | 108 ++++++++++++++++++++++++++---------------------------- 1 file changed, 51 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index ae9a3554..8b8bb535 100644 --- a/README.md +++ b/README.md @@ -52,14 +52,13 @@ If you're not familiar with Composer, please see . 1. Add php-resque to your application's composer.json. ```json - - { - ... - "require": { - "chrisboulton/php-resque": "1.2.x" - }, - ... - } +{ + //... + "require": { + "chrisboulton/php-resque": "1.2.x" + }, + // ... +} ``` 2. Run `composer install`. @@ -68,7 +67,7 @@ If you're not familiar with Composer, please see . initialization file. (example) ```sh - require 'vendor/autoload.php'; +require 'vendor/autoload.php'; ``` ## Jobs ## @@ -78,15 +77,13 @@ If you're not familiar with Composer, please see . Jobs are queued as follows: ```php +// Required if redis is located elsewhere +Resque::setBackend('localhost:6379'); - // Required if redis is located elsewhere - Resque::setBackend('localhost:6379'); - - $args = array( - 'name' => 'Chris' - ); - Resque::enqueue('default', 'My_Job', $args); - +$args = array( + 'name' => 'Chris' + ); +Resque::enqueue('default', 'My_Job', $args); ``` ### Defining Jobs ### @@ -94,16 +91,14 @@ Jobs are queued as follows: Each job should be in it's own class, and include a `perform` method. ```php - - class My_Job - { - public function perform() - { - // Work work work - echo $this->args['name']; - } - } - +class My_Job +{ + public function perform() + { + // Work work work + echo $this->args['name']; + } +} ``` When the job is run, the class will be instantiated and any arguments @@ -120,24 +115,23 @@ The `tearDown` method if defined, will be called after the job finishes. ```php +class My_Job +{ + public function setUp() + { + // ... Set up environment for this job + } + + public function perform() + { + // .. Run job + } - class My_Job + public function tearDown() { - public function setUp() - { - // ... Set up environment for this job - } - - public function perform() - { - // .. Run job - } - - public function tearDown() - { - // ... Remove environment for this job - } + // ... Remove environment for this job } +} ``` ### Tracking Job Statuses ### @@ -151,15 +145,15 @@ To track the status of a job, pass `true` as the fourth argument to returned: ```php - $token = Resque::enqueue('default', 'My_Job', $args, true); - echo $token; +$token = Resque::enqueue('default', 'My_Job', $args, true); +echo $token; ``` To fetch the status of a job: ```php - $status = new Resque_Job_Status($token); - echo $status->get(); // Outputs the status +$status = new Resque_Job_Status($token); +echo $status->get(); // Outputs the status ``` Job statuses are defined as constants in the `Resque_Job_Status` class. @@ -191,15 +185,15 @@ not having a single environment such as with Ruby, the PHP port makes *no* assumptions about your setup. To start a worker, it's very similar to the Ruby version: - - $ QUEUE=file_serve php bin/resque - +```sh +$ QUEUE=file_serve php bin/resque +``` It's your responsibility to tell the worker which file to include to get your application underway. You do so by setting the `APP_INCLUDE` environment variable: ```sh - $ QUEUE=file_serve APP_INCLUDE=../application/init.php php bin/resque +$ QUEUE=file_serve APP_INCLUDE=../application/init.php php bin/resque ``` *Pro tip: Using Composer? More than likely, you don't need to worry about @@ -216,8 +210,8 @@ Setting `VERBOSE` will print basic debugging information and `VVERBOSE` will print detailed information. ```sh - $ VERBOSE QUEUE=file_serve bin/resque - $ VVERBOSE QUEUE=file_serve bin/resque +$ VERBOSE QUEUE=file_serve bin/resque +$ VVERBOSE QUEUE=file_serve bin/resque ``` ### Priorities and Queue Lists ### @@ -230,7 +224,7 @@ checked in. As per the original example: ```sh - $ QUEUE=file_serve,warm_cache bin/resque +$ QUEUE=file_serve,warm_cache bin/resque ``` The `file_serve` queue will always be checked for new jobs on each @@ -242,7 +236,7 @@ All queues are supported in the same manner and processed in alphabetical order: ```sh - $ QUEUE=* bin/resque +$ QUEUE=* bin/resque ``` ### Running Multiple Workers ### @@ -251,7 +245,7 @@ Multiple workers ca be launched and automatically worked by supplying the `COUNT` environment variable: ```sh - $ COUNT=5 bin/resque +$ COUNT=5 bin/resque ``` ### Custom prefix ### @@ -260,7 +254,7 @@ When you have multiple apps using the same Redis database it is better to use a custom prefix to separate the Resque data: ```sh - $ PREFIX=my-app-name bin/resque +$ PREFIX=my-app-name bin/resque ``` ### Forking ### @@ -308,7 +302,7 @@ and supplying a callback that you would like triggered when the event is raised: ```sh - Resque_Event::listen('eventName', [callback]); +Resque_Event::listen('eventName', [callback]); ``` `[callback]` may be anything in PHP that is callable by `call_user_func_array`: From 03d31830d1f8bae8d58aa8dccb9f25a1373359b0 Mon Sep 17 00:00:00 2001 From: Alexander Kotynia Date: Thu, 22 Aug 2013 11:32:56 +0300 Subject: [PATCH 113/194] Fix notice for: 'Undefined variable: logger' --- bin/resque | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/resque b/bin/resque index b9a10cf6..b8089ac8 100755 --- a/bin/resque +++ b/bin/resque @@ -61,7 +61,7 @@ if($APP_INCLUDE) { // See if the APP_INCLUDE containes a logger object, // If none exists, fallback to internal logger -if (!isset($logger) && !is_object($logger)) { +if (!isset($logger) || !is_object($logger)) { $logger = new Resque_Log($logLevel); } From 10c1d0b75e1eeb66bd3df9e33c79c1ff2169959d Mon Sep 17 00:00:00 2001 From: Petr Trofimov Date: Fri, 23 Aug 2013 12:17:47 +0300 Subject: [PATCH 114/194] Resque/Worker: removed reestablishConnection --- lib/Resque/Worker.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index a6c3985f..67807bd5 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -350,7 +350,6 @@ private function registerSigHandlers() pcntl_signal(SIGUSR1, array($this, 'killChild')); pcntl_signal(SIGUSR2, array($this, 'pauseProcessing')); pcntl_signal(SIGCONT, array($this, 'unPauseProcessing')); - pcntl_signal(SIGPIPE, array($this, 'reestablishRedisConnection')); $this->logger->log(Psr\Log\LogLevel::DEBUG, 'Registered signals'); } @@ -373,16 +372,6 @@ public function unPauseProcessing() $this->paused = false; } - /** - * Signal handler for SIGPIPE, in the event the redis connection has gone away. - * Attempts to reconnect to redis, or raises an Exception. - */ - public function reestablishRedisConnection() - { - $this->logger->log(Psr\Log\LogLevel::NOTICE, 'SIGPIPE received; attempting to reconnect'); - Resque::redis()->establishConnection(); - } - /** * Schedule a worker for shutdown. Will finish processing the current job * and when the timeout interval is reached, the worker will shut down. From 62dfa93458618e1b33a0bc39e4a5d3831b92ded1 Mon Sep 17 00:00:00 2001 From: Richard K Miller Date: Wed, 4 Sep 2013 10:29:01 -0600 Subject: [PATCH 115/194] cli_set_process_title() available in PHP 5.5 to set proc title. This is preferred over the PECL function setproctitle(). --- lib/Resque/Worker.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index a6c3985f..1c9219ad 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -324,7 +324,10 @@ private function startup() */ private function updateProcLine($status) { - if(function_exists('setproctitle')) { + if(function_exists('cli_set_process_title')) { + cli_set_process_title('resque-' . Resque::VERSION . ': ' . $status); + } + else if(function_exists('setproctitle')) { setproctitle('resque-' . Resque::VERSION . ': ' . $status); } } From 6ed8fc048f1a82865ac3ff74e0f7dc26be1d7811 Mon Sep 17 00:00:00 2001 From: Richard K Miller Date: Wed, 4 Sep 2013 12:29:38 -0600 Subject: [PATCH 116/194] refactor process title to keep it DRY --- lib/Resque/Worker.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 1c9219ad..d74505ce 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -324,11 +324,12 @@ private function startup() */ private function updateProcLine($status) { + $processTitle = 'resque-' . Resque::VERSION . ': ' . $status; if(function_exists('cli_set_process_title')) { - cli_set_process_title('resque-' . Resque::VERSION . ': ' . $status); + cli_set_process_title($processTitle); } else if(function_exists('setproctitle')) { - setproctitle('resque-' . Resque::VERSION . ': ' . $status); + setproctitle($processTitle); } } From 9335ef51b463511f7a94c59048491b3f8990623e Mon Sep 17 00:00:00 2001 From: Richard K Miller Date: Wed, 4 Sep 2013 16:12:12 -0600 Subject: [PATCH 117/194] fix spaces that should be tabs --- lib/Resque/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index d74505ce..7499039f 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -324,7 +324,7 @@ private function startup() */ private function updateProcLine($status) { - $processTitle = 'resque-' . Resque::VERSION . ': ' . $status; + $processTitle = 'resque-' . Resque::VERSION . ': ' . $status; if(function_exists('cli_set_process_title')) { cli_set_process_title($processTitle); } From 473d610a277416042c163fecbc96866bf9bfc607 Mon Sep 17 00:00:00 2001 From: Lee Boynton Date: Mon, 4 Nov 2013 11:58:23 +0000 Subject: [PATCH 118/194] Fixed incorrect link to credis GitHub page --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6f11965..9e86e513 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ Redisent has always been the Redis backend for php-resque because of its lightweight nature. Unfortunately, Redisent is largely unmaintained. -[Credis](http://example.com/) is a fork of Redisent, which among other improvements will automatically use the [phpredis](https://github.com/nicolasff/phpredis) native PHP extension if it is available. (you want this for speed, trust me) +[Credis](https://github.com/colinmollenhour/credis) is a fork of Redisent, which among other improvements will automatically use the [phpredis](https://github.com/nicolasff/phpredis) native PHP extension if it is available. (you want this for speed, trust me) php-resque now utilizes Credis for all Redis based operations. Credis automatically required and installed as a Composer dependency. @@ -71,4 +71,4 @@ Composer support has been improved and is now the recommended method for includi ## 1.0 (2010-04-18) ## -* Initial release \ No newline at end of file +* Initial release From 6d8cd501b739433749c58047f1befe7129fecdd3 Mon Sep 17 00:00:00 2001 From: Michael Alexander Date: Tue, 12 Nov 2013 13:11:48 +1100 Subject: [PATCH 119/194] Added token as an argument to the afterEnqueue callback --- README.md | 1 + lib/Resque.php | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 8b8bb535..e247c219 100644 --- a/README.md +++ b/README.md @@ -384,6 +384,7 @@ Called after a job has been queued using the `Resque::enqueue` method. Arguments * Class - string containing the name of scheduled job * Arguments - array of arguments supplied to the job * Queue - string containing the name of the queue the job was added to +* Token - string containing the new token of the enqueued job ## Contributors ## diff --git a/lib/Resque.php b/lib/Resque.php index e01ab750..1bba5dac 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -189,6 +189,7 @@ public static function enqueue($queue, $class, $args = null, $trackStatus = fals 'class' => $class, 'args' => $args, 'queue' => $queue, + 'token' => $result, )); } From f91352d8100d1960d0ba13bb17337940ee96e7c3 Mon Sep 17 00:00:00 2001 From: Michael Alexander Date: Mon, 18 Nov 2013 10:02:03 +1100 Subject: [PATCH 120/194] Renamed references of token to id. --- README.md | 2 +- lib/Resque.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e247c219..662c970f 100644 --- a/README.md +++ b/README.md @@ -384,7 +384,7 @@ Called after a job has been queued using the `Resque::enqueue` method. Arguments * Class - string containing the name of scheduled job * Arguments - array of arguments supplied to the job * Queue - string containing the name of the queue the job was added to -* Token - string containing the new token of the enqueued job +* Id - string containing the new token of the enqueued job ## Contributors ## diff --git a/lib/Resque.php b/lib/Resque.php index 1bba5dac..2b47084c 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -189,7 +189,7 @@ public static function enqueue($queue, $class, $args = null, $trackStatus = fals 'class' => $class, 'args' => $args, 'queue' => $queue, - 'token' => $result, + 'id' => $result, )); } From b7e3ee5221a1c42b535cb214da155a3e283e5206 Mon Sep 17 00:00:00 2001 From: Benji Date: Sun, 24 Nov 2013 17:27:36 -0800 Subject: [PATCH 121/194] Fixes the examples for using VERBOSE and VVERBOSE The example for the VERBOSE and VVERBOSE options would throw a 'command not found' error when attempting to use it in the same manner as it was originally documented. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8b8bb535..4d0b5b71 100644 --- a/README.md +++ b/README.md @@ -210,8 +210,8 @@ Setting `VERBOSE` will print basic debugging information and `VVERBOSE` will print detailed information. ```sh -$ VERBOSE QUEUE=file_serve bin/resque -$ VVERBOSE QUEUE=file_serve bin/resque +$ VERBOSE=1 QUEUE=file_serve bin/resque +$ VVERBOSE=1 QUEUE=file_serve bin/resque ``` ### Priorities and Queue Lists ### From 8ccc31632acda3f5f1a13788a27fd2a07aa2e9d3 Mon Sep 17 00:00:00 2001 From: jingyu liu Date: Fri, 6 Dec 2013 14:14:57 +0800 Subject: [PATCH 122/194] repair PHP Notice, on line 17 when run , it has a PHP Notice. I think it's right command . --- demo/queue.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/demo/queue.php b/demo/queue.php index 52f2f0ba..870086ec 100644 --- a/demo/queue.php +++ b/demo/queue.php @@ -13,6 +13,10 @@ 'test' => 'test', ), ); +if (empty($argv[2])) { + $jobId = Resque::enqueue('default', $argv[1], $args, true); +} else { + $jobId = Resque::enqueue($argv[1], $argv[2], $args, true); +} -$jobId = Resque::enqueue($argv[1], $argv[2], $args, true); -echo "Queued job ".$jobId."\n\n"; \ No newline at end of file +echo "Queued job ".$jobId."\n\n"; From 3a62e47f1654a0999c33ac7bdacc3526ee682ec0 Mon Sep 17 00:00:00 2001 From: Daniel Hunsaker Date: Sat, 7 Dec 2013 00:38:16 -0700 Subject: [PATCH 123/194] Created HOWITWORKS; cleanup of README Addresses a request from @chrisboulton in GitHub issue #149 Slight grammar cleanup and content update in README.md Mention of HOWITWORKS.md in README.md, referring those who want to know more that direction Expanded and slightly cleaner version of a comment made in #149 that prompted this commit/PR was placed in HOWITWORKS.md Signed-off-by: Daniel Hunsaker --- HOWITWORKS.md | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 129 +++++++++++++++++++++++++++-------------- 2 files changed, 243 insertions(+), 43 deletions(-) create mode 100644 HOWITWORKS.md diff --git a/HOWITWORKS.md b/HOWITWORKS.md new file mode 100644 index 00000000..ec85fa37 --- /dev/null +++ b/HOWITWORKS.md @@ -0,0 +1,157 @@ +*For an overview of how to __use__ php-resque, see `README.md`.* + +The following is a step-by-step breakdown of how php-resque operates. + +## Enqueue Job ## + +What happens when you call `Resque::enqueue()`? + +1. `Resque::enqueue()` calls `Resque_Job::create()` with the same arguments it + received. +2. `Resque_Job::create()` checks that your `$args` (the third argument) are + either `null` or in an array +3. `Resque_Job::create()` generates a job ID (a "token" in most of the docs) +4. `Resque_Job::create()` pushes the job to the requested queue (first + argument) +5. `Resque_Job::create()`, if status monitoring is enabled for the job (fourth + argument), calls `Resque_Job_Status::create()` with the job ID as its only + argument +6. `Resque_Job_Status::create()` creates a key in Redis with the job ID in its + name, and the current status (as well as a couple of timestamps) as its + value, then returns control to `Resque_Job::create()` +7. `Resque_Job::create()` returns control to `Resque::enqueue()`, with the job + ID as a return value +8. `Resque::enqueue()` triggers the `afterEnqueue` event, then returns control + to your application, again with the job ID as its return value + +## Workers At Work ## + +How do the workers process the queues? + +1. `Resque_Worker::work()`, the main loop of the worker process, calls + `Resque_Worker->reserve()` to check for a job +2. `Resque_Worker->reserve()` checks whether to use blocking pops or not (from + `BLOCKING`), then acts accordingly: + * Blocking Pop + 1. `Resque_Worker->reserve()` calls `Resque_Job::reserveBlocking()` with + the entire queue list and the timeout (from `INTERVAL`) as arguments + 2. `Resque_Job::reserveBlocking()` calls `Resque::blpop()` (which in turn + calls Redis' `blpop`, after prepping the queue list for the call, then + processes the response for consistency with other aspects of the + library, before finally returning control [and the queue/content of the + retrieved job, if any] to `Resque_Job::reserveBlocking()`) + 3. `Resque_Job::reserveBlocking()` checks whether the job content is an + array (it should contain the job's type [class], payload [args], and + ID), and aborts processing if not + 4. `Resque_Job::reserveBlocking()` creates a new `Resque_Job` object with + the queue and content as constructor arguments to initialize the job + itself, and returns it, along with control of the process, to + `Resque_Worker->reserve()` + * Queue Polling + 1. `Resque_Worker->reserve()` iterates through the queue list, calling + `Resque_Job::reserve()` with the current queue's name as the sole + argument on each pass + 2. `Resque_Job::reserve()` passes the queue name on to `Resque::pop()`, + which in turn calls Redis' `lpop` with the same argument, then returns + control (and the job content, if any) to `Resque_Job::reserve()` + 3. `Resque_Job::reserve()` checks whether the job content is an array (as + before, it should contain the job's type [class], payload [args], and + ID), and aborts processing if not + 4. `Resque_Job::reserve()` creates a new `Resque_Job` object in the same + manner as above, and also returns this object (along with control of + the process) to `Resque_Worker->reserve()` +3. In either case, `Resque_Worker->reserve()` returns the new `Resque_Job` + object, along with control, up to `Resque_Worker::work()`; if no job is + found, it simply returns `FALSE` + * No Jobs + 1. If blocking mode is not enabled, `Resque_Worker::work()` sleeps for + `INTERVAL` seconds; it calls `usleep()` for this, so fractional seconds + *are* supported + * Job Reserved + 1. `Resque_Worker::work()` triggers a `beforeFork` event + 2. `Resque_Worker::work()` calls `Resque_Worker->workingOn()` with the new + `Resque_Job` object as its argument + 3. `Resque_Worker->workingOn()` does some reference assignments to help keep + track of the worker/job relationship, then updates the job status from + `WAITING` to `RUNNING` + 4. `Resque_Worker->workingOn()` stores the new `Resque_Job` object's payload + in a Redis key associated to the worker itself (this is to prevent the job + from being lost indefinitely, but does rely on that PID never being + allocated on that host to a different worker process), then returns control + to `Resque_Worker::work()` + 5. `Resque_Worker::work()` forks a child process to run the actual `perform()` + 6. The next steps differ between the worker and the child, now running in + separate processes: + * Worker + 1. The worker waits for the job process to complete + 2. If the exit status is not 0, the worker calls `Resque_Job->fail()` with + a `Resque_Job_DirtyExitException` as its only argument. + 3. `Resque_Job->fail()` triggers an `onFailure` event + 4. `Resque_Job->fail()` updates the job status from `RUNNING` to `FAILED` + 5. `Resque_Job->fail()` calls `Resque_Failure::create()` with the job + payload, the `Resque_Job_DirtyExitException`, the internal ID of the + worker, and the queue name as arguments + 6. `Resque_Failure::create()` creates a new object of whatever type has + been set as the `Resque_Failure` "backend" handler; by default, this is + a `Resque_Failure_Redis` object, whose constructor simply collects the + data passed into `Resque_Failure::create()` and pushes it into Redis + in the `failed` queue + 7. `Resque_Job->fail()` increments two failure counters in Redis: one for + a total count, and one for the worker + 8. `Resque_Job->fail()` returns control to the worker (still in + `Resque_Worker::work()`) without a value + * Job + 1. The job calls `Resque_Worker->perform()` with the `Resque_Job` as its + only argument. + 2. `Resque_Worker->perform()` sets up a `try...catch` block so it can + properly handle exceptions by marking jobs as failed (by calling + `Resque_Job->fail()`, as above) + 3. Inside the `try...catch`, `Resque_Worker->perform()` triggers an + `afterFork` event + 4. Still inside the `try...catch`, `Resque_Worker->perform()` calls + `Resque_Job->perform()` with no arguments + 5. `Resque_Job->perform()` calls `Resque_Job->getInstance()` with no + arguments + 6. If `Resque_Job->getInstance()` has already been called, it returns the + existing instance; otherwise: + 7. `Resque_Job->getInstance()` checks that the job's class (type) exists + and has a `perform()` method; if not, in either case, it throws an + exception which will be caught by `Resque_Worker->perform()` + 8. `Resque_Job->getInstance()` creates an instance of the job's class, and + initializes it with a reference to the `Resque_Job` itself, the job's + arguments (which it gets by calling `Resque_Job->getArguments()`, which + in turn simply returns the value of `args[0]`, or an empty array if no + arguments were passed), and the queue name + 9. `Resque_Job->getInstance()` returns control, along with the job class + instance, to `Resque_Job->perform()` + 10. `Resque_Job->perform()` sets up its own `try...catch` block to handle + `Resque_Job_DontPerform` exceptions; any other exceptions are passed + up to `Resque_Worker->perform()` + 11. `Resque_Job->perform()` triggers a `beforePerform` event + 12. `Resque_Job->perform()` calls `setUp()` on the instance, if it exists + 13. `Resque_Job->perform()` calls `perform()` on the instance + 14. `Resque_Job->perform()` calls `tearDown()` on the instance, if it + exists + 15. `Resque_Job->perform()` triggers an `afterPerform` event + 16. The `try...catch` block ends, suppressing `Resque_Job_DontPerform` + exceptions by returning control, and the value `FALSE`, to + `Resque_Worker->perform()`; any other situation returns the value + `TRUE` along with control, instead + 17. The `try...catch` block in `Resque_Worker->perform()` ends + 18. `Resque_Worker->perform()` updates the job status from `RUNNING` to + `COMPLETE`, then returns control, with no value, to the worker (again + still in `Resque_Worker::work()`) + 19. `Resque_Worker::work()` calls `exit(0)` to terminate the job process + cleanly + * SPECIAL CASE: Non-forking OS (Windows) + 1. Same as the job above, except it doesn't call `exit(0)` when done + 7. `Resque_Worker::work()` calls `Resque_Worker->doneWorking()` with no + arguments + 8. `Resque_Worker->doneWorking()` increments two processed counters in Redis: + one for a total count, and one for the worker + 9. `Resque_Worker->doneWorking()` deletes the Redis key set in + `Resque_Worker->workingOn()`, then returns control, with no value, to + `Resque_Worker::work()` +4. `Resque_Worker::work()` returns control to the beginning of the main loop, + where it will wait for the next job to become available, and start this + process all over again \ No newline at end of file diff --git a/README.md b/README.md index 2e13a764..06afc722 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ php-resque: PHP Resque Worker (and Enqueue) [![Build Status](https://secure.trav =========================================== Resque is a Redis-backed library for creating background jobs, placing -those jobs on multiple queues, and processing them later. +those jobs on one or more queues, and processing them later. ## Background ## @@ -24,7 +24,7 @@ The PHP port provides much the same features as the Ruby version: * Workers can be distributed between multiple machines * Includes support for priorities (queues) -* Resilient to memory leaks (fork) +* Resilient to memory leaks (forking) * Expects failure It also supports the following additional features: @@ -53,9 +53,9 @@ If you're not familiar with Composer, please see . ```json { - //... + // ... "require": { - "chrisboulton/php-resque": "1.2.x" + "chrisboulton/php-resque": "1.2.x" // Most recent tagged version }, // ... } @@ -88,7 +88,7 @@ Resque::enqueue('default', 'My_Job', $args); ### Defining Jobs ### -Each job should be in it's own class, and include a `perform` method. +Each job should be in its own class, and include a `perform` method. ```php class My_Job @@ -111,7 +111,7 @@ result in a job failing. Jobs can also have `setUp` and `tearDown` methods. If a `setUp` method is defined, it will be called before the `perform` method is run. -The `tearDown` method if defined, will be called after the job finishes. +The `tearDown` method, if defined, will be called after the job finishes. ```php @@ -138,7 +138,7 @@ class My_Job php-resque has the ability to perform basic status tracking of a queued job. The status information will allow you to check if a job is in the -queue, currently being run, has finished, or failed. +queue, is currently being run, has finished, or has failed. To track the status of a job, pass `true` as the fourth argument to `Resque::enqueue`. A token used for tracking the job status will be @@ -185,9 +185,11 @@ not having a single environment such as with Ruby, the PHP port makes *no* assumptions about your setup. To start a worker, it's very similar to the Ruby version: + ```sh $ QUEUE=file_serve php bin/resque ``` + It's your responsibility to tell the worker which file to include to get your application underway. You do so by setting the `APP_INCLUDE` environment variable: @@ -203,6 +205,10 @@ your application too!* Getting your application underway also includes telling the worker your job classes, by means of either an autoloader or including them. +Alternately, you can always `include('bin/resque')` from your application and +skip setting `APP_INCLUDE` altogether. Just be sure the various environment +variables are set (`setenv`) before you do. + ### Logging ### The port supports the same environment variables for logging to STDOUT. @@ -236,18 +242,23 @@ All queues are supported in the same manner and processed in alphabetical order: ```sh -$ QUEUE=* bin/resque +$ QUEUE='*' bin/resque ``` ### Running Multiple Workers ### -Multiple workers ca be launched and automatically worked by supplying -the `COUNT` environment variable: +Multiple workers can be launched simultaneously by supplying the `COUNT` +environment variable: ```sh $ COUNT=5 bin/resque ``` +Be aware, however, that each worker is its own fork, and the original process +will shut down as soon as it has spawned `COUNT` forks. If you need to keep +track of your workers using an external application such as `monit`, you'll +need to work around this limitation. + ### Custom prefix ### When you have multiple apps using the same Redis database it is better to @@ -272,9 +283,9 @@ the job. Signals also work on supported platforms exactly as in the Ruby version of Resque: -* `QUIT` - Wait for child to finish processing then exit -* `TERM` / `INT` - Immediately kill child then exit -* `USR1` - Immediately kill child but don't exit +* `QUIT` - Wait for job to finish processing then exit +* `TERM` / `INT` - Immediately kill job then exit +* `USR1` - Immediately kill job but don't exit * `USR2` - Pause worker, no new jobs will be processed * `CONT` - Resume worker. @@ -286,11 +297,12 @@ and any forked children also set their process title with the job being run. This helps identify running processes on the server and their resque status. -**PHP does not have this functionality by default.** +**PHP does not have this functionality by default until 5.5.** A PECL module () exists that -adds this funcitonality to PHP, so if you'd like process titles updated, -install the PECL module as well. php-resque will detect and use it. +adds this functionality to PHP before 5.5, so if you'd like process +titles updated, install the PECL module as well. php-resque will +automatically detect and use it. ## Event/Hook System ## @@ -310,7 +322,7 @@ Resque_Event::listen('eventName', [callback]); * A string with the name of a function * An array containing an object and method to call * An array containing an object and a static method to call -* A closure (PHP 5.3) +* A closure (PHP 5.3+) Events may pass arguments (documented below), so your callback should accept these arguments. @@ -342,20 +354,20 @@ Called before php-resque forks to run a job. Argument passed contains the instan `Resque_Job` for the job about to be run. `beforeFork` is triggered in the **parent** process. Any changes made will be permanent -for as long as the worker lives. +for as long as the **worker** lives. #### afterFork #### Called after php-resque forks to run a job (but before the job is run). Argument passed contains the instance of `Resque_Job` for the job about to be run. -`afterFork` is triggered in the child process after forking out to complete a job. Any -changes made will only live as long as the job is being processed. +`afterFork` is triggered in the **child** process after forking out to complete a job. Any +changes made will only live as long as the **job** is being processed. #### beforePerform #### Called before the `setUp` and `perform` methods on a job are run. Argument passed -contains the instance of `Resque_Job` about for the job about to be run. +contains the instance of `Resque_Job` for the job about to be run. You can prevent execution of the job by throwing an exception of `Resque_Job_DontPerform`. Any other exceptions thrown will be treated as if they were thrown in a job, causing the @@ -384,28 +396,59 @@ Called after a job has been queued using the `Resque::enqueue` method. Arguments * Class - string containing the name of scheduled job * Arguments - array of arguments supplied to the job * Queue - string containing the name of the queue the job was added to -* Id - string containing the new token of the enqueued job +* ID - string containing the new token of the enqueued job + +## Step-By-Step ## + +For a more in-depth look at what php-resque does under the hood (without +needing to directly examine the code), have a look at `HOWITWORKS.md`. ## Contributors ## -* chrisboulton -* thedotedge -* hobodave -* scraton -* KevBurnsJr -* jmathai -* dceballos -* patrickbajao -* andrewjshults -* warezthebeef -* d11wtq -* hlegius -* salimane -* humancopy -* pedroarnal -* chaitanyakuber -* maetl -* Matt Heath -* jjfrey -* scragg0x -* ruudk +### Project Lead ### + +* @chrisboulton + +### Others ### + +* @acinader +* @ajbonner +* @andrewjshults +* @atorres757 +* @benjisg +* @cballou +* @chaitanyakuber +* @charly22 +* @CyrilMazur +* @d11wtq +* @danhunsaker +* @dceballos +* @ebernhardson +* @hlegius +* @hobodave +* @humancopy +* @JesseObrien +* @jjfrey +* @jmathai +* @joshhawthorne +* @KevBurnsJr +* @lboynton +* @maetl +* @matteosister +* @MattHeath +* @mickhrmweb +* @Olden +* @patrickbajao +* @pedroarnal +* @ptrofimov +* @rajibahmed +* @richardkmiller +* @Rockstar04 +* @ruudk +* @salimane +* @scragg0x +* @scraton +* @thedotedge +* @tonypiper +* @trimbletodd +* @warezthebeef From cdc5c3f357eed309ec4affccb40583ed1282d45a Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Fri, 20 Dec 2013 12:21:52 +0100 Subject: [PATCH 124/194] Set Resque_Log in constructor --- lib/Resque/Worker.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index d94aef54..d08504c7 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -49,6 +49,11 @@ class Resque_Worker */ private $child = null; + public function __construct() + { + $this->logger = new Resque_Log(); + } + /** * Return all workers known to Resque as instantiated instances. * @return array From aeabb5bb200c1ec91b42209282129428cb9b921c Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Fri, 20 Dec 2013 12:24:24 +0100 Subject: [PATCH 125/194] Constructor on top with default logger --- lib/Resque/Worker.php | 55 ++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index d08504c7..379b853e 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -49,9 +49,34 @@ class Resque_Worker */ private $child = null; - public function __construct() + /** + * Instantiate a new worker, given a list of queues that it should be working + * on. The list of queues should be supplied in the priority that they should + * be checked for jobs (first come, first served) + * + * Passing a single '*' allows the worker to work on all queues in alphabetical + * order. You can easily add new queues dynamically and have them worked on using + * this method. + * + * @param string|array $queues String with a single queue name, array with multiple. + */ + public function __construct($queues) { $this->logger = new Resque_Log(); + + if(!is_array($queues)) { + $queues = array($queues); + } + + $this->queues = $queues; + if(function_exists('gethostname')) { + $hostname = gethostname(); + } + else { + $hostname = php_uname('n'); + } + $this->hostname = $hostname; + $this->id = $this->hostname . ':'.getmypid() . ':' . implode(',', $this->queues); } /** @@ -112,34 +137,6 @@ public function setId($workerId) $this->id = $workerId; } - /** - * Instantiate a new worker, given a list of queues that it should be working - * on. The list of queues should be supplied in the priority that they should - * be checked for jobs (first come, first served) - * - * Passing a single '*' allows the worker to work on all queues in alphabetical - * order. You can easily add new queues dynamically and have them worked on using - * this method. - * - * @param string|array $queues String with a single queue name, array with multiple. - */ - public function __construct($queues) - { - if(!is_array($queues)) { - $queues = array($queues); - } - - $this->queues = $queues; - if(function_exists('gethostname')) { - $hostname = gethostname(); - } - else { - $hostname = php_uname('n'); - } - $this->hostname = $hostname; - $this->id = $this->hostname . ':'.getmypid() . ':' . implode(',', $this->queues); - } - /** * The primary loop for a worker which when called on an instance starts * the worker's life cycle. From ad33efbc675f19450d4f3c5edc5a37ac7e1ac724 Mon Sep 17 00:00:00 2001 From: Iskandar Najmuddin Date: Mon, 5 May 2014 13:02:16 +0000 Subject: [PATCH 126/194] Improve Resque_Redis DSN parsing. - Allow for DSN URIs to work as expected. - Backward-compatible with simple 'host:port' format. - Does not parse DSNs provided in array format for Credis_Cluster. --- lib/Resque/Redis.php | 123 +++++++++++++++++++------- test/Resque/Tests/DsnTest.php | 157 ++++++++++++++++++++++++++++++++++ 2 files changed, 247 insertions(+), 33 deletions(-) mode change 100644 => 100755 lib/Resque/Redis.php create mode 100755 test/Resque/Tests/DsnTest.php diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php old mode 100644 new mode 100755 index 6cef3d2d..e44a9627 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -8,14 +8,29 @@ */ class Resque_Redis { - /** - * Redis namespace - * @var string - */ - private static $defaultNamespace = 'resque:'; + /** + * Redis namespace + * @var string + */ + private static $defaultNamespace = 'resque:'; + + /** + * A default host to connect to + */ + const DEFAULT_HOST = 'localhost'; + + /** + * The default Redis port + */ + const DEFAULT_PORT = 6379; + + /** + * The default Redis Database number + */ + const DEFAULT_DATABASE = 0; - private $server; - private $database; + private $server; + private $database; /** * @var array List of all commands in Redis that supply a key as their @@ -92,40 +107,36 @@ public static function prefix($namespace) self::$defaultNamespace = $namespace; } - public function __construct($server, $database = null) + /** + * @param string|array $server A DSN or array + * @param int $database A database number to select + */ + public function __construct($server, $database = null) { $this->server = $server; $this->database = $database; if (is_array($this->server)) { $this->driver = new Credis_Cluster($server); - } - else { - $port = null; - $password = null; - $host = $server; - - // If not a UNIX socket path or tcp:// formatted connections string - // assume host:port combination. - if (strpos($server, '/') === false) { - $parts = explode(':', $server); - if (isset($parts[1])) { - $port = $parts[1]; - } - $host = $parts[0]; - }else if (strpos($server, 'redis://') !== false){ - // Redis format is: - // redis://[user]:[password]@[host]:[port] - list($userpwd,$hostport) = explode('@', $server); - $userpwd = substr($userpwd, strpos($userpwd, 'redis://')+8); - list($host, $port) = explode(':', $hostport); - list($user, $password) = explode(':', $userpwd); - } - - $this->driver = new Credis_Client($host, $port); - if (isset($password)){ + + } else { + + list($host, $port, $dsnDatabase, $user, $password, $options) = $this->parseDsn($server); + // $user is are unused here + + // Look for known Credis_Client options + $timeout = isset($options['timeout']) ? intval($options['timeout']) : null; + $persistent = isset($options['persistent']) ? $options['persistent'] : ''; + + $this->driver = new Credis_Client($host, $port, $timeout, $persistent); + if ($password){ $this->driver->auth($password); } + + // If the `$database` constructor argument is not set, use the value from the DSN. + if (is_null($database)) { + $database = $dsnDatabase; + } } if ($this->database !== null) { @@ -133,6 +144,52 @@ public function __construct($server, $database = null) } } + /** + * Parse a DSN string + * @param string $dsn + * @return array [host, port, db, user, pass, options] + */ + public function parseDsn($dsn) + { + $validSchemes = array('redis', 'tcp'); + if ($dsn == '') { + // Use a sensible default for an empty DNS string + $dsn = 'redis://' . self::DEFAULT_HOST; + } + $parts = parse_url(http://github.com/$dsn); + if (isset($parts['scheme']) && ! in_array($parts['scheme'], $validSchemes)) { + throw new \InvalidArgumentException("Invalid DSN. Supported schemes are " . implode(', ', $validSchemes)); + } + + // Allow simple 'hostname' format, which parse_url treats as a path, not host. + if ( ! isset($parts['host'])) { + $parts = array('host' => $parts['path']); + } + + $port = isset($parts['port']) ? intval($parts['port']) : self::DEFAULT_PORT; + + $database = self::DEFAULT_DATABASE; + if (isset($parts['path'])) { + // Strip non-digit chars from path + $database = intval(preg_replace('/[^0-9]/', '', $parts['path'])); + } + + $options = array(); + if (isset($parts['query'])) { + // Parse the query string into an array + parse_str($parts['query'], $options); + } + + return array( + $parts['host'], + $port, + $database, + isset($parts['user']) ? $parts['user'] : false, + isset($parts['pass']) ? $parts['pass'] : false, + $options, + ); + } + /** * Magic method to handle all function requests and prefix key based * operations with the {self::$defaultNamespace} key prefix. diff --git a/test/Resque/Tests/DsnTest.php b/test/Resque/Tests/DsnTest.php new file mode 100755 index 00000000..c9cd4713 --- /dev/null +++ b/test/Resque/Tests/DsnTest.php @@ -0,0 +1,157 @@ + + * @license http://www.opensource.org/licenses/mit-license.php + */ +class Resque_Tests_DsnTest extends Resque_Tests_TestCase +{ + + /** + * These DNS strings are considered valid. + * + * @return array + */ + public function validDsnStringProvider() + { + return array( + // Input , Expected output + array('', array( + 'localhost', + Resque_Redis::DEFAULT_PORT, + Resque_Redis::DEFAULT_DATABASE, + false, false, + array(), + )), + array('localhost', array( + 'localhost', + Resque_Redis::DEFAULT_PORT, + Resque_Redis::DEFAULT_DATABASE, + false, false, + array(), + )), + array('localhost:1234', array( + 'localhost', + 1234, + Resque_Redis::DEFAULT_DATABASE, + false, false, + array(), + )), + array('localhost:1234/2', array( + 'localhost', + 1234, + 2, + false, false, + array(), + )), + array('redis://foobar', array( + 'foobar', + Resque_Redis::DEFAULT_PORT, + Resque_Redis::DEFAULT_DATABASE, + false, false, + array(), + )), + array('redis://foobar:1234', array( + 'foobar', + 1234, + Resque_Redis::DEFAULT_DATABASE, + false, false, + array(), + )), + array('redis://user@foobar:1234', array( + 'foobar', + 1234, + Resque_Redis::DEFAULT_DATABASE, + 'user', false, + array(), + )), + array('redis://user:pass@foobar:1234', array( + 'foobar', + 1234, + Resque_Redis::DEFAULT_DATABASE, + 'user', 'pass', + array(), + )), + array('redis://user:pass@foobar:1234?x=y&a=b', array( + 'foobar', + 1234, + Resque_Redis::DEFAULT_DATABASE, + 'user', 'pass', + array('x' => 'y', 'a' => 'b'), + )), + array('redis://:pass@foobar:1234?x=y&a=b', array( + 'foobar', + 1234, + Resque_Redis::DEFAULT_DATABASE, + false, 'pass', + array('x' => 'y', 'a' => 'b'), + )), + array('redis://user@foobar:1234?x=y&a=b', array( + 'foobar', + 1234, + Resque_Redis::DEFAULT_DATABASE, + 'user', false, + array('x' => 'y', 'a' => 'b'), + )), + array('redis://foobar:1234?x=y&a=b', array( + 'foobar', + 1234, + Resque_Redis::DEFAULT_DATABASE, + false, false, + array('x' => 'y', 'a' => 'b'), + )), + array('redis://user@foobar:1234/12?x=y&a=b', array( + 'foobar', + 1234, + 12, + 'user', false, + array('x' => 'y', 'a' => 'b'), + )), + array('tcp://user@foobar:1234/12?x=y&a=b', array( + 'foobar', + 1234, + 12, + 'user', false, + array('x' => 'y', 'a' => 'b'), + )), + ); + } + + /** + * These DSN values should throw exceptions + * @return array + */ + public function bogusDsnStringProvider() + { + return array( + 'http://foo.bar/', + '://foo.bar/', + 'user:@foobar:1234?x=y&a=b', + 'foobar:1234?x=y&a=b', + ); + } + + /** + * @dataProvider validDsnStringProvider + */ + public function testParsingValidDsnString($dsn, $expected) + { + $resqueRedis = new Resque_Redis('localhost'); + $result = $resqueRedis->parseDsn($dsn); + $this->assertEquals($expected, $result); + } + + /** + * @dataProvider bogusDsnStringProvider + * @expectedException InvalidArgumentException + */ + public function testParsingBogusDsnStringThrowsException($dsn) + { + $resqueRedis = new Resque_Redis('localhost'); + // The next line should throw an InvalidArgumentException + $result = $resqueRedis->parseDsn($dsn); + } + +} From 1abbad3f5ee83ef05b19199bdbb29f7176c5eb7d Mon Sep 17 00:00:00 2001 From: Iskandar Najmuddin Date: Mon, 5 May 2014 14:47:43 +0000 Subject: [PATCH 127/194] Improve comments and readability --- demo/check_status.php | 3 +++ demo/queue.php | 4 ++++ lib/Resque.php | 2 +- lib/Resque/Redis.php | 43 +++++++++++++++++++++++++---------- test/Resque/Tests/DsnTest.php | 14 ++++++++++++ 5 files changed, 53 insertions(+), 13 deletions(-) mode change 100644 => 100755 demo/check_status.php mode change 100644 => 100755 demo/queue.php mode change 100644 => 100755 lib/Resque.php diff --git a/demo/check_status.php b/demo/check_status.php old mode 100644 new mode 100755 index 645bf6d9..871dabab --- a/demo/check_status.php +++ b/demo/check_status.php @@ -7,6 +7,9 @@ date_default_timezone_set('GMT'); Resque::setBackend('127.0.0.1:6379'); +// You can also use a DSN-style format: +//Resque::setBackend('redis://user:pass@127.0.0.1:6379'); +//Resque::setBackend('redis://user:pass@a.host.name:3432/2'); $status = new Resque_Job_Status($argv[1]); if(!$status->isTracking()) { diff --git a/demo/queue.php b/demo/queue.php old mode 100644 new mode 100755 index 52f2f0ba..1eca1244 --- a/demo/queue.php +++ b/demo/queue.php @@ -7,6 +7,10 @@ date_default_timezone_set('GMT'); Resque::setBackend('127.0.0.1:6379'); +// You can also use a DSN-style format: +//Resque::setBackend('redis://user:pass@127.0.0.1:6379'); +//Resque::setBackend('redis://user:pass@a.host.name:3432/2'); + $args = array( 'time' => time(), 'array' => array( diff --git a/lib/Resque.php b/lib/Resque.php old mode 100644 new mode 100755 index 2b47084c..13c841e6 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -32,7 +32,7 @@ class Resque * Given a host/port combination separated by a colon, set it as * the redis server that Resque will talk to. * - * @param mixed $server Host/port combination separated by a colon, or + * @param mixed $server Host/port combination separated by a colon, DSN-formatted URI, or * a nested array of servers with host/port pairs. * @param int $database */ diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index e44a9627..41fec070 100755 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -122,7 +122,7 @@ public function __construct($server, $database = null) } else { list($host, $port, $dsnDatabase, $user, $password, $options) = $this->parseDsn($server); - // $user is are unused here + // $user is not used, only $password // Look for known Credis_Client options $timeout = isset($options['timeout']) ? intval($options['timeout']) : null; @@ -133,9 +133,11 @@ public function __construct($server, $database = null) $this->driver->auth($password); } - // If the `$database` constructor argument is not set, use the value from the DSN. - if (is_null($database)) { + // If we have found a database in our DSN, use it instead of the `$database` + // value passed into the constructor + if ($dsnDatabase !== false) { $database = $dsnDatabase; + $this->database = $database; } } @@ -145,35 +147,52 @@ public function __construct($server, $database = null) } /** - * Parse a DSN string - * @param string $dsn + * Parse a DSN string, which can have one of the following formats: + * + * - host:port + * - redis://user:pass@host:port/db?option1=val1&option2=val2 + * - tcp://user:pass@host:port/db?option1=val1&option2=val2 + * + * Note: the 'user' part of the DSN is not used. + * + * @param string $dsn A DSN string * @return array [host, port, db, user, pass, options] */ public function parseDsn($dsn) { - $validSchemes = array('redis', 'tcp'); if ($dsn == '') { // Use a sensible default for an empty DNS string $dsn = 'redis://' . self::DEFAULT_HOST; } $parts = parse_url(http://github.com/$dsn); + + // Check the URI scheme + $validSchemes = array('redis', 'tcp'); if (isset($parts['scheme']) && ! in_array($parts['scheme'], $validSchemes)) { throw new \InvalidArgumentException("Invalid DSN. Supported schemes are " . implode(', ', $validSchemes)); } - // Allow simple 'hostname' format, which parse_url treats as a path, not host. - if ( ! isset($parts['host'])) { - $parts = array('host' => $parts['path']); + // Allow simple 'hostname' format, which `parse_url` treats as a path, not host. + if ( ! isset($parts['host']) && isset($parts['path'])) { + $parts['host'] = $parts['path']; + unset($parts['path']); } + // Extract the port number as an integer $port = isset($parts['port']) ? intval($parts['port']) : self::DEFAULT_PORT; - $database = self::DEFAULT_DATABASE; + // Get the database from the 'path' part of the URI + $database = false; if (isset($parts['path'])) { // Strip non-digit chars from path $database = intval(preg_replace('/[^0-9]/', '', $parts['path'])); } + // Extract any 'user' and 'pass' values + $user = isset($parts['user']) ? $parts['user'] : false; + $pass = isset($parts['pass']) ? $parts['pass'] : false; + + // Convert the query string into an associative array $options = array(); if (isset($parts['query'])) { // Parse the query string into an array @@ -184,8 +203,8 @@ public function parseDsn($dsn) $parts['host'], $port, $database, - isset($parts['user']) ? $parts['user'] : false, - isset($parts['pass']) ? $parts['pass'] : false, + $user, + $pass, $options, ); } diff --git a/test/Resque/Tests/DsnTest.php b/test/Resque/Tests/DsnTest.php index c9cd4713..2fc66541 100755 --- a/test/Resque/Tests/DsnTest.php +++ b/test/Resque/Tests/DsnTest.php @@ -60,6 +60,13 @@ public function validDsnStringProvider() false, false, array(), )), + array('redis://foobar:1234/15', array( + 'foobar', + 1234, + 15, + false, false, + array(), + )), array('redis://user@foobar:1234', array( 'foobar', 1234, @@ -67,6 +74,13 @@ public function validDsnStringProvider() 'user', false, array(), )), + array('redis://user@foobar:1234/15', array( + 'foobar', + 1234, + 15, + 'user', false, + array(), + )), array('redis://user:pass@foobar:1234', array( 'foobar', 1234, From d1d2b3b3545dfae139cec69aa1d93de4676f6beb Mon Sep 17 00:00:00 2001 From: Iskandar Najmuddin Date: Mon, 5 May 2014 14:55:01 +0000 Subject: [PATCH 128/194] Test for 'false' database value when not found in DSN --- lib/Resque/Redis.php | 5 +++-- test/Resque/Tests/DsnTest.php | 29 ++++++++++++++++++----------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 41fec070..be5492a7 100755 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -109,7 +109,8 @@ public static function prefix($namespace) /** * @param string|array $server A DSN or array - * @param int $database A database number to select + * @param int $database A database number to select. However, if we find a valid database number in the DSN the + * DSN-supplied value will be used instead and this parameter is ignored. */ public function __construct($server, $database = null) { @@ -134,7 +135,7 @@ public function __construct($server, $database = null) } // If we have found a database in our DSN, use it instead of the `$database` - // value passed into the constructor + // value passed into the constructor. if ($dsnDatabase !== false) { $database = $dsnDatabase; $this->database = $database; diff --git a/test/Resque/Tests/DsnTest.php b/test/Resque/Tests/DsnTest.php index 2fc66541..7e483a3f 100755 --- a/test/Resque/Tests/DsnTest.php +++ b/test/Resque/Tests/DsnTest.php @@ -21,21 +21,21 @@ public function validDsnStringProvider() array('', array( 'localhost', Resque_Redis::DEFAULT_PORT, - Resque_Redis::DEFAULT_DATABASE, + false, false, false, array(), )), array('localhost', array( 'localhost', Resque_Redis::DEFAULT_PORT, - Resque_Redis::DEFAULT_DATABASE, + false, false, false, array(), )), array('localhost:1234', array( 'localhost', 1234, - Resque_Redis::DEFAULT_DATABASE, + false, false, false, array(), )), @@ -49,14 +49,14 @@ public function validDsnStringProvider() array('redis://foobar', array( 'foobar', Resque_Redis::DEFAULT_PORT, - Resque_Redis::DEFAULT_DATABASE, + false, false, false, array(), )), array('redis://foobar:1234', array( 'foobar', 1234, - Resque_Redis::DEFAULT_DATABASE, + false, false, false, array(), )), @@ -67,10 +67,17 @@ public function validDsnStringProvider() false, false, array(), )), + array('redis://foobar:1234/0', array( + 'foobar', + 1234, + 0, + false, false, + array(), + )), array('redis://user@foobar:1234', array( 'foobar', 1234, - Resque_Redis::DEFAULT_DATABASE, + false, 'user', false, array(), )), @@ -84,35 +91,35 @@ public function validDsnStringProvider() array('redis://user:pass@foobar:1234', array( 'foobar', 1234, - Resque_Redis::DEFAULT_DATABASE, + false, 'user', 'pass', array(), )), array('redis://user:pass@foobar:1234?x=y&a=b', array( 'foobar', 1234, - Resque_Redis::DEFAULT_DATABASE, + false, 'user', 'pass', array('x' => 'y', 'a' => 'b'), )), array('redis://:pass@foobar:1234?x=y&a=b', array( 'foobar', 1234, - Resque_Redis::DEFAULT_DATABASE, + false, false, 'pass', array('x' => 'y', 'a' => 'b'), )), array('redis://user@foobar:1234?x=y&a=b', array( 'foobar', 1234, - Resque_Redis::DEFAULT_DATABASE, + false, 'user', false, array('x' => 'y', 'a' => 'b'), )), array('redis://foobar:1234?x=y&a=b', array( 'foobar', 1234, - Resque_Redis::DEFAULT_DATABASE, + false, false, false, array('x' => 'y', 'a' => 'b'), )), From 62ed6200831e525d67c961df3523e3088c51bffd Mon Sep 17 00:00:00 2001 From: Iskandar Najmuddin Date: Mon, 5 May 2014 14:59:37 +0000 Subject: [PATCH 129/194] Put 'else' keyword on new line in keeping with project conventions --- lib/Resque/Redis.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index be5492a7..bddd0134 100755 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -120,7 +120,8 @@ public function __construct($server, $database = null) if (is_array($this->server)) { $this->driver = new Credis_Cluster($server); - } else { + } + else { list($host, $port, $dsnDatabase, $user, $password, $options) = $this->parseDsn($server); // $user is not used, only $password From 506b769b905ede790f77e74b15e877cc3c03b289 Mon Sep 17 00:00:00 2001 From: Iskandar Najmuddin Date: Mon, 5 May 2014 15:08:00 +0000 Subject: [PATCH 130/194] Make parseDsn() method static, remove unused member vars --- lib/Resque.php | 7 +--- lib/Resque/Redis.php | 66 ++++++++++++++++------------------- test/Resque/Tests/DsnTest.php | 6 ++-- 3 files changed, 33 insertions(+), 46 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index 13c841e6..0f4b94e1 100755 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -54,12 +54,7 @@ public static function redis() return self::$redis; } - $server = self::$redisServer; - if (empty($server)) { - $server = 'localhost:6379'; - } - - self::$redis = new Resque_Redis($server, self::$redisDatabase); + self::$redis = new Resque_Redis(self::$redisServer, self::$redisDatabase); return self::$redis; } diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index bddd0134..a946b14b 100755 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -29,9 +29,6 @@ class Resque_Redis */ const DEFAULT_DATABASE = 0; - private $server; - private $database; - /** * @var array List of all commands in Redis that supply a key as their * first argument. Used to prefix keys with the Resque namespace. @@ -114,16 +111,12 @@ public static function prefix($namespace) */ public function __construct($server, $database = null) { - $this->server = $server; - $this->database = $database; - - if (is_array($this->server)) { + if (is_array($server)) { $this->driver = new Credis_Cluster($server); - } else { - list($host, $port, $dsnDatabase, $user, $password, $options) = $this->parseDsn($server); + list($host, $port, $dsnDatabase, $user, $password, $options) = self::parseDsn($server); // $user is not used, only $password // Look for known Credis_Client options @@ -139,11 +132,10 @@ public function __construct($server, $database = null) // value passed into the constructor. if ($dsnDatabase !== false) { $database = $dsnDatabase; - $this->database = $database; } } - if ($this->database !== null) { + if ($database !== null) { $this->driver->select($database); } } @@ -158,9 +150,10 @@ public function __construct($server, $database = null) * Note: the 'user' part of the DSN is not used. * * @param string $dsn A DSN string - * @return array [host, port, db, user, pass, options] + * @return array An array of DSN compotnents, with 'false' values for any unknown components. e.g. + * [host, port, db, user, pass, options] */ - public function parseDsn($dsn) + public static function parseDsn($dsn) { if ($dsn == '') { // Use a sensible default for an empty DNS string @@ -219,37 +212,38 @@ public function parseDsn($dsn) * @param array $args Array of supplied arguments to the method. * @return mixed Return value from Resident::call() based on the command. */ - public function __call($name, $args) { - if(in_array($name, $this->keyCommands)) { - if(is_array($args[0])) { - foreach($args[0] AS $i => $v) { - $args[0][$i] = self::$defaultNamespace . $v; - } - } else { - $args[0] = self::$defaultNamespace . $args[0]; - } + public function __call($name, $args) + { + if (in_array($name, $this->keyCommands)) { + if (is_array($args[0])) { + foreach ($args[0] AS $i => $v) { + $args[0][$i] = self::$defaultNamespace . $v; + } + } + else { + $args[0] = self::$defaultNamespace . $args[0]; + } } try { return $this->driver->__call($name, $args); } - catch(CredisException $e) { + catch (CredisException $e) { return false; } } - public static function getPrefix() - { - return self::$defaultNamespace; - } + public static function getPrefix() + { + return self::$defaultNamespace; + } - public static function removePrefix($string) - { - $prefix=self::getPrefix(); + public static function removePrefix($string) + { + $prefix=self::getPrefix(); - if (substr($string, 0, strlen($prefix)) == $prefix) { - $string = substr($string, strlen($prefix), strlen($string) ); - } - return $string; - } + if (substr($string, 0, strlen($prefix)) == $prefix) { + $string = substr($string, strlen($prefix), strlen($string) ); + } + return $string; + } } -?> \ No newline at end of file diff --git a/test/Resque/Tests/DsnTest.php b/test/Resque/Tests/DsnTest.php index 7e483a3f..282a0882 100755 --- a/test/Resque/Tests/DsnTest.php +++ b/test/Resque/Tests/DsnTest.php @@ -159,8 +159,7 @@ public function bogusDsnStringProvider() */ public function testParsingValidDsnString($dsn, $expected) { - $resqueRedis = new Resque_Redis('localhost'); - $result = $resqueRedis->parseDsn($dsn); + $result = Resque_Redis::parseDsn($dsn); $this->assertEquals($expected, $result); } @@ -170,9 +169,8 @@ public function testParsingValidDsnString($dsn, $expected) */ public function testParsingBogusDsnStringThrowsException($dsn) { - $resqueRedis = new Resque_Redis('localhost'); // The next line should throw an InvalidArgumentException - $result = $resqueRedis->parseDsn($dsn); + $result = Resque_Redis::parseDsn($dsn); } } From b0385d29594fc91da4bc78c0209b8a8c69ae5763 Mon Sep 17 00:00:00 2001 From: Iskandar Najmuddin Date: Mon, 5 May 2014 15:11:20 +0000 Subject: [PATCH 131/194] Add comment describing REDIS_BACKEND format to bin/resque --- bin/resque | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bin/resque b/bin/resque index b8089ac8..4cb50da5 100755 --- a/bin/resque +++ b/bin/resque @@ -30,7 +30,15 @@ if(empty($QUEUE)) { die("Set QUEUE env var containing the list of queues to work.\n"); } +/** + * REDIS_BACKEND can have simple 'host:port' format or use a DSN-style format like this: + * - redis://user:pass@host:port + * + * Note: the 'user' part of the DSN URI is required but is not used. + */ $REDIS_BACKEND = getenv('REDIS_BACKEND'); + +// A redis database number $REDIS_BACKEND_DB = getenv('REDIS_BACKEND_DB'); if(!empty($REDIS_BACKEND)) { if (empty($REDIS_BACKEND_DB)) From 76412df8fd519af2b7bcc51ae209e3dc5cb80b39 Mon Sep 17 00:00:00 2001 From: Iskandar Najmuddin Date: Mon, 5 May 2014 15:29:52 +0000 Subject: [PATCH 132/194] Fix return array format of `bogusDsnStringProvider` --- test/Resque/Tests/DsnTest.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/test/Resque/Tests/DsnTest.php b/test/Resque/Tests/DsnTest.php index 282a0882..086db1ea 100755 --- a/test/Resque/Tests/DsnTest.php +++ b/test/Resque/Tests/DsnTest.php @@ -53,6 +53,13 @@ public function validDsnStringProvider() false, false, array(), )), + array('redis://foobar/', array( + 'foobar', + Resque_Redis::DEFAULT_PORT, + false, + false, false, + array(), + )), array('redis://foobar:1234', array( 'foobar', 1234, @@ -147,10 +154,9 @@ public function validDsnStringProvider() public function bogusDsnStringProvider() { return array( - 'http://foo.bar/', - '://foo.bar/', - 'user:@foobar:1234?x=y&a=b', - 'foobar:1234?x=y&a=b', + array('http://foo.bar/'), + array('user:@foobar:1234?x=y&a=b'), + array('foobar:1234?x=y&a=b'), ); } From 3b074a046a16f8b3b463ae6de056e4fb2945c6eb Mon Sep 17 00:00:00 2001 From: Iskandar Najmuddin Date: Mon, 5 May 2014 17:47:39 +0000 Subject: [PATCH 133/194] Revert file modes back to 644 --- demo/check_status.php | 0 demo/queue.php | 0 lib/Resque.php | 0 lib/Resque/Redis.php | 0 test/Resque/Tests/DsnTest.php | 0 5 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 demo/check_status.php mode change 100755 => 100644 demo/queue.php mode change 100755 => 100644 lib/Resque.php mode change 100755 => 100644 lib/Resque/Redis.php mode change 100755 => 100644 test/Resque/Tests/DsnTest.php diff --git a/demo/check_status.php b/demo/check_status.php old mode 100755 new mode 100644 diff --git a/demo/queue.php b/demo/queue.php old mode 100755 new mode 100644 diff --git a/lib/Resque.php b/lib/Resque.php old mode 100755 new mode 100644 diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php old mode 100755 new mode 100644 diff --git a/test/Resque/Tests/DsnTest.php b/test/Resque/Tests/DsnTest.php old mode 100755 new mode 100644 From 65288538e3642fbb916d2c9d1f615addffe49c21 Mon Sep 17 00:00:00 2001 From: Dayson Pais Date: Mon, 26 May 2014 17:16:19 +0530 Subject: [PATCH 134/194] More verbose logging if a Job throws an exception Presently, the logger just logs the primary error message with no stack trace of additional debugging information. Type casting the exception to a string gives a much efficient output and enables better debugging. --- lib/Resque/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index d94aef54..7105a7bc 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -241,7 +241,7 @@ public function perform(Resque_Job $job) $job->perform(); } catch(Exception $e) { - $this->logger->log(Psr\Log\LogLevel::CRITICAL, '{job} has failed {stack}', array('job' => $job, 'stack' => $e->getMessage())); +g $this->logger->log(Psr\Log\LogLevel::CRITICAL, '{job} has failed {stack}', array('job' => $job, 'stack' => (string)$e); $job->fail($e); return; } From b242280ecdfbbbce4de1648610b96cc0c128707f Mon Sep 17 00:00:00 2001 From: Dayson Pais Date: Mon, 26 May 2014 21:53:28 +0530 Subject: [PATCH 135/194] Removed erroneously introduced character. --- lib/Resque/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 7105a7bc..4f7ef0cb 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -241,7 +241,7 @@ public function perform(Resque_Job $job) $job->perform(); } catch(Exception $e) { -g $this->logger->log(Psr\Log\LogLevel::CRITICAL, '{job} has failed {stack}', array('job' => $job, 'stack' => (string)$e); + $this->logger->log(Psr\Log\LogLevel::CRITICAL, '{job} has failed {stack}', array('job' => $job, 'stack' => (string)$e); $job->fail($e); return; } From 760e38c0efca7353a411a5e785e541fbb48ab76d Mon Sep 17 00:00:00 2001 From: Dayson Pais Date: Mon, 26 May 2014 22:01:49 +0530 Subject: [PATCH 136/194] Fixed syntax error --- lib/Resque/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 4f7ef0cb..2d6f6494 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -241,7 +241,7 @@ public function perform(Resque_Job $job) $job->perform(); } catch(Exception $e) { - $this->logger->log(Psr\Log\LogLevel::CRITICAL, '{job} has failed {stack}', array('job' => $job, 'stack' => (string)$e); + $this->logger->log(Psr\Log\LogLevel::CRITICAL, '{job} has failed {stack}', array('job' => $job, 'stack' => (string)$e)); $job->fail($e); return; } From 40d2ec8c77ab85d1e7f218286d5fe2c4409f9ab8 Mon Sep 17 00:00:00 2001 From: Todd Burry Date: Mon, 23 Jun 2014 08:20:23 -0400 Subject: [PATCH 137/194] Make the credis requirements less strict. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since credis has moved forward, but is backwards compatible, resque shouldn’t be so strict towards an old version because other libraries need newer credis features. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index fb868bc6..6e31daac 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "php": ">=5.3.0", "ext-pcntl": "*", - "colinmollenhour/credis": "1.2.*", + "colinmollenhour/credis": "~1.2", "psr/log": "1.0.0" }, "suggest": { From 0327217907adce5f17d88c276f5be94833b2bb53 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Thu, 26 Jun 2014 19:07:52 +1000 Subject: [PATCH 138/194] call beforePerform before retrieving an instance of the job class --- lib/Resque/Job.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index ddc37d04..23ae7a43 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -186,10 +186,10 @@ public function getInstance() */ public function perform() { - $instance = $this->getInstance(); try { Resque_Event::trigger('beforePerform', $this); + $instance = $this->getInstance(); if(method_exists($instance, 'setUp')) { $instance->setUp(); } From 51524e8ebcfc3cee0662763cbd2064710a5a77b7 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Thu, 26 Jun 2014 19:09:31 +1000 Subject: [PATCH 139/194] update changelog --- CHANGELOG.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e86e513..a68db63e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,15 +17,11 @@ Composer support has been improved and is now the recommended method for includi ### Other Improvements/Changes * **COMPATIBILITY BREAKING**: The bundled worker manager `resque.php` has been moved to `bin/resque`, and is available as `vendor/bin/resque` when php-resque is installed as a Composer package. - * Restructure tests and test bootstrapping. Autoload tests via Composer (install test dependencies with `composer install --dev`) - * Add `SETEX` to list of commands which supply a key as the first argument in Redisent (danhunsaker) - * Fix an issue where a lost connection to Redis could cause an infinite loop (atorres757) - * Add a helper method to `Resque_Redis` to remove the namespace applied to Redis keys (tonypiper) - +* Call beforePerform hook before retrieivng an instance of the job class (allows beforePerform to cancel a job with DontPerform before initialising your application) ## 1.2 (2012-10-13) ## From 3cca6312ca90cc2068fabd00e3fa9d8ef0116f9a Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Thu, 26 Jun 2014 19:19:04 +1000 Subject: [PATCH 140/194] update changelog and contributors docs --- CHANGELOG.md | 11 +++++++++++ README.md | 1 + 2 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a68db63e..a77d5beb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,17 @@ php-resque now utilizes Credis for all Redis based operations. Credis automatica Composer support has been improved and is now the recommended method for including php-resque in your project. Details on Composer support can be found in the Getting Started section of the readme. +### Improved DSN Support + +Changes by iskandar introduce improved support for using DSNs to connect to Redis. You can now utilize the following formatted strings for the REDIS_BACKEND environment variable to connect: + +* `host` +* `host:port` +* `redis://host:port` +* `redis://host:port/db` +* `redis://user:pass@host:port/` (username is required but will be ignored) +* `tcp://user:pass@host:port/` (username is required but will be ignored) + ### Other Improvements/Changes * **COMPATIBILITY BREAKING**: The bundled worker manager `resque.php` has been moved to `bin/resque`, and is available as `vendor/bin/resque` when php-resque is installed as a Composer package. diff --git a/README.md b/README.md index 06afc722..068a57e5 100644 --- a/README.md +++ b/README.md @@ -427,6 +427,7 @@ needing to directly examine the code), have a look at `HOWITWORKS.md`. * @hlegius * @hobodave * @humancopy +* @iskandar * @JesseObrien * @jjfrey * @jmathai From bcfd6b79f72f86a41e9100d3b21203e1b2918cfb Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Thu, 26 Jun 2014 21:03:46 +1000 Subject: [PATCH 141/194] update composer.lock --- composer.lock | 156 +++++++++++++++++++++++++++----------------------- 1 file changed, 84 insertions(+), 72 deletions(-) diff --git a/composer.lock b/composer.lock index 1a84e922..1ecf21a5 100644 --- a/composer.lock +++ b/composer.lock @@ -1,22 +1,23 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" ], - "hash": "646010a06695709794f1bc38392e392f", + "hash": "1862fac0c6f40ddf7d98bcef5f4bbd77", "packages": [ { "name": "colinmollenhour/credis", - "version": "1.2", + "version": "1.4", "source": { "type": "git", "url": "https://github.com/colinmollenhour/credis.git", - "reference": "1.2" + "reference": "2079564c61cc49867eddc3cc918c711564164d65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/colinmollenhour/credis/zipball/1.2", - "reference": "1.2", + "url": "https://api.github.com/repos/colinmollenhour/credis/zipball/2079564c61cc49867eddc3cc918c711564164d65", + "reference": "2079564c61cc49867eddc3cc918c711564164d65", "shasum": "" }, "require": { @@ -41,20 +42,20 @@ ], "description": "Credis is a lightweight interface to the Redis key-value store which wraps the phpredis library when available for better performance.", "homepage": "https://github.com/colinmollenhour/credis", - "time": "2013-03-19 02:57:04" + "time": "2014-05-05 19:31:30" }, { "name": "psr/log", "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/php-fig/log", - "reference": "1.0.0" + "url": "https://github.com/php-fig/log.git", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" }, "dist": { "type": "zip", - "url": "https://github.com/php-fig/log/archive/1.0.0.zip", - "reference": "1.0.0", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", "shasum": "" }, "type": "library", @@ -85,32 +86,37 @@ "packages-dev": [ { "name": "phpunit/php-code-coverage", - "version": "1.2.11", + "version": "1.2.17", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "1.2.11" + "reference": "6ef2bf3a1c47eca07ea95f0d8a902a6340390b34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.11", - "reference": "1.2.11", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6ef2bf3a1c47eca07ea95f0d8a902a6340390b34", + "reference": "6ef2bf3a1c47eca07ea95f0d8a902a6340390b34", "shasum": "" }, "require": { "php": ">=5.3.3", "phpunit/php-file-iterator": ">=1.3.0@stable", - "phpunit/php-text-template": ">=1.1.1@stable", + "phpunit/php-text-template": ">=1.2.0@stable", "phpunit/php-token-stream": ">=1.1.3@stable" }, "require-dev": { - "phpunit/phpunit": "3.7.*" + "phpunit/phpunit": "3.7.*@dev" }, "suggest": { "ext-dom": "*", "ext-xdebug": ">=2.0.5" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, "autoload": { "classmap": [ "PHP/" @@ -137,20 +143,20 @@ "testing", "xunit" ], - "time": "2013-05-23 18:23:24" + "time": "2014-03-28 10:53:45" }, { "name": "phpunit/php-file-iterator", - "version": "1.3.3", + "version": "1.3.4", "source": { "type": "git", - "url": "git://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "1.3.3" + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" }, "dist": { "type": "zip", - "url": "https://github.com/sebastianbergmann/php-file-iterator/zipball/1.3.3", - "reference": "1.3.3", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", "shasum": "" }, "require": { @@ -177,25 +183,25 @@ } ], "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "http://www.phpunit.de/", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", "keywords": [ "filesystem", "iterator" ], - "time": "2012-10-11 04:44:38" + "time": "2013-10-10 15:34:57" }, { "name": "phpunit/php-text-template", - "version": "1.1.4", + "version": "1.2.0", "source": { "type": "git", - "url": "git://github.com/sebastianbergmann/php-text-template.git", - "reference": "1.1.4" + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" }, "dist": { "type": "zip", - "url": "https://github.com/sebastianbergmann/php-text-template/zipball/1.1.4", - "reference": "1.1.4", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", "shasum": "" }, "require": { @@ -226,20 +232,20 @@ "keywords": [ "template" ], - "time": "2012-10-31 11:15:28" + "time": "2014-01-30 17:20:04" }, { "name": "phpunit/php-timer", - "version": "1.0.4", + "version": "1.0.5", "source": { "type": "git", - "url": "git://github.com/sebastianbergmann/php-timer.git", - "reference": "1.0.4" + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" }, "dist": { "type": "zip", - "url": "https://github.com/sebastianbergmann/php-timer/zipball/1.0.4", - "reference": "1.0.4", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", "shasum": "" }, "require": { @@ -266,24 +272,24 @@ } ], "description": "Utility class for timing", - "homepage": "http://www.phpunit.de/", + "homepage": "https://github.com/sebastianbergmann/php-timer/", "keywords": [ "timer" ], - "time": "2012-10-11 04:45:58" + "time": "2013-08-02 07:42:54" }, { "name": "phpunit/php-token-stream", - "version": "1.1.5", + "version": "1.2.2", "source": { "type": "git", - "url": "git://github.com/sebastianbergmann/php-token-stream.git", - "reference": "1.1.5" + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32" }, "dist": { "type": "zip", - "url": "https://github.com/sebastianbergmann/php-token-stream/zipball/1.1.5", - "reference": "1.1.5", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32", + "reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32", "shasum": "" }, "require": { @@ -291,6 +297,11 @@ "php": ">=5.3.3" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, "autoload": { "classmap": [ "PHP/" @@ -311,47 +322,46 @@ } ], "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "http://www.phpunit.de/", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", "keywords": [ "tokenizer" ], - "time": "2012-10-11 04:47:14" + "time": "2014-03-03 05:10:30" }, { "name": "phpunit/phpunit", - "version": "3.7.21", + "version": "3.7.37", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "3.7.21" + "reference": "ae6cefd7cc84586a5ef27e04bae11ee940ec63dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.21", - "reference": "3.7.21", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ae6cefd7cc84586a5ef27e04bae11ee940ec63dc", + "reference": "ae6cefd7cc84586a5ef27e04bae11ee940ec63dc", "shasum": "" }, "require": { + "ext-ctype": "*", "ext-dom": "*", + "ext-json": "*", "ext-pcre": "*", "ext-reflection": "*", "ext-spl": "*", "php": ">=5.3.3", - "phpunit/php-code-coverage": ">=1.2.1,<1.3.0", - "phpunit/php-file-iterator": ">=1.3.1", - "phpunit/php-text-template": ">=1.1.1", - "phpunit/php-timer": ">=1.0.2,<1.1.0", - "phpunit/phpunit-mock-objects": ">=1.2.0,<1.3.0", - "symfony/yaml": ">=2.0,<3.0" + "phpunit/php-code-coverage": "~1.2", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.1", + "phpunit/php-timer": "~1.0", + "phpunit/phpunit-mock-objects": "~1.2", + "symfony/yaml": "~2.0" }, "require-dev": { - "pear-pear/pear": "1.9.4" + "pear-pear.php.net/pear": "1.9.4" }, "suggest": { - "ext-json": "*", - "ext-simplexml": "*", - "ext-tokenizer": "*", - "phpunit/php-invoker": ">=1.1.0,<1.2.0" + "phpunit/php-invoker": "~1.1" }, "bin": [ "composer/bin/phpunit" @@ -389,20 +399,20 @@ "testing", "xunit" ], - "time": "2013-05-23 18:54:29" + "time": "2014-04-30 12:24:19" }, { "name": "phpunit/phpunit-mock-objects", "version": "1.2.3", "source": { "type": "git", - "url": "git://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "1.2.3" + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875" }, "dist": { "type": "zip", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects/archive/1.2.3.zip", - "reference": "1.2.3", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/5794e3c5c5ba0fb037b11d8151add2a07fa82875", + "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875", "shasum": "" }, "require": { @@ -442,17 +452,17 @@ }, { "name": "symfony/yaml", - "version": "v2.3.1", + "version": "v2.5.0", "target-dir": "Symfony/Component/Yaml", "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "v2.3.1" + "reference": "b4b09c68ec2f2727574544ef0173684281a5033c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.3.1", - "reference": "v2.3.1", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/b4b09c68ec2f2727574544ef0173684281a5033c", + "reference": "b4b09c68ec2f2727574544ef0173684281a5033c", "shasum": "" }, "require": { @@ -461,7 +471,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -476,7 +486,9 @@ "authors": [ { "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org/", + "role": "Lead Developer" }, { "name": "Symfony Community", @@ -485,7 +497,7 @@ ], "description": "Symfony Yaml Component", "homepage": "http://symfony.com/", - "time": "2013-05-10 18:12:13" + "time": "2014-05-16 14:25:18" } ], "aliases": [ From 006d7502d956849b9f205ec7ce8060497b7b4441 Mon Sep 17 00:00:00 2001 From: vincent zhao Date: Fri, 8 Aug 2014 10:25:40 +1000 Subject: [PATCH 142/194] add an enqueued timestamp to the job payload --- lib/Resque/Job.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 23ae7a43..ca21445a 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -62,6 +62,7 @@ public static function create($queue, $class, $args = null, $monitor = false) 'class' => $class, 'args' => array($args), 'id' => $id, + 'queue_time' => microtime(true), )); if($monitor) { From 295ec7d68a2c6f9d2db056afbe9582b8238ed19c Mon Sep 17 00:00:00 2001 From: kazusuke sasezaki Date: Fri, 29 Aug 2014 00:56:23 +0900 Subject: [PATCH 143/194] add PHP 5.5, 5.6 to .travis.yml --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index d8dd5f89..cf099782 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,8 @@ language: php php: - 5.3 - 5.4 + - 5.5 + - 5.6 env: - REDIS_STANDALONE=0 - REDIS_STANDALONE=1 From 98fde571db008a8b48e73022599d1d1c07d4a7b5 Mon Sep 17 00:00:00 2001 From: Wedy Chainy Date: Fri, 19 Sep 2014 21:29:53 +1000 Subject: [PATCH 144/194] Turn on redis command 'rename' --- .gitignore | 3 ++- lib/Resque/Redis.php | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index a725465a..a47ff2d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -vendor/ \ No newline at end of file +vendor/ +*.swp diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index a946b14b..574e085c 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -76,7 +76,8 @@ class Resque_Redis 'zcard', 'zscore', 'zremrangebyscore', - 'sort' + 'sort', + 'rename' ); // sinterstore // sunion @@ -85,7 +86,6 @@ class Resque_Redis // sdiffstore // sinter // smove - // rename // rpoplpush // mget // msetnx From 4a97c1462829a4f8592ae56949f22c850875832e Mon Sep 17 00:00:00 2001 From: Wedy Chainy Date: Wed, 17 Sep 2014 10:20:26 +1000 Subject: [PATCH 145/194] dequeue --- README.md | 16 ++++ lib/Resque.php | 150 ++++++++++++++++++++++++++-------- lib/Resque/Redis.php | 2 +- test/Resque/Tests/JobTest.php | 75 ++++++++++++++++- 4 files changed, 208 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 068a57e5..3a1860d8 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,22 @@ class My_Job } ``` +### Dequeueing Jobs ### + +This method can be used to conveniently remove a job from a queue. + +```php +// Removes 'My_Job' of queue 'default' +Resque::dequeue('default', ['My_Job']); +``` + +If no jobs are given, this method will dequeue all jobs matching the provided queue. + +```php +// Removes all jobs of queue 'default' +Resque::dequeue('default'); +``` + ### Tracking Job Statuses ### php-resque has the ability to perform basic status tracking of a queued diff --git a/lib/Resque.php b/lib/Resque.php index 0f4b94e1..c83b6017 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -120,39 +120,55 @@ public static function pop($queue) return json_decode($item, true); } - /** - * Pop an item off the end of the specified queues, using blocking list pop, - * decode it and return it. - * - * @param array $queues - * @param int $timeout - * @return null|array Decoded item from the queue. - */ - public static function blpop(array $queues, $timeout) - { - $list = array(); - foreach($queues AS $queue) { - $list[] = 'queue:' . $queue; - } - - $item = self::redis()->blpop($list, (int)$timeout); - - if(!$item) { - return; - } - - /** - * Normally the Resque_Redis class returns queue names without the prefix - * But the blpop is a bit different. It returns the name as prefix:queue:name - * So we need to strip off the prefix:queue: part - */ - $queue = substr($item[0], strlen(self::redis()->getPrefix() . 'queue:')); - - return array( - 'queue' => $queue, - 'payload' => json_decode($item[1], true) - ); - } + /** + * Remove items of the specified queue + * + * @param string $queue The name of the queue to fetch an item from. + * @param array $items + * @return integer number of deleted items + */ + public static function dequeue($queue, $items = Array()) + { + if(count($items) > 0) { + return self::removeItems($queue, $items); + } else { + return self::removeList($queue); + } + } + + /** + * Pop an item off the end of the specified queues, using blocking list pop, + * decode it and return it. + * + * @param array $queues + * @param int $timeout + * @return null|array Decoded item from the queue. + */ + public static function blpop(array $queues, $timeout) + { + $list = array(); + foreach($queues AS $queue) { + $list[] = 'queue:' . $queue; + } + + $item = self::redis()->blpop($list, (int)$timeout); + + if(!$item) { + return; + } + + /** + * Normally the Resque_Redis class returns queue names without the prefix + * But the blpop is a bit different. It returns the name as prefix:queue:name + * So we need to strip off the prefix:queue: part + */ + $queue = substr($item[0], strlen(self::redis()->getPrefix() . 'queue:')); + + return array( + 'queue' => $queue, + 'payload' => json_decode($item[1], true) + ); + } /** * Return the size (number of pending jobs) of the specified queue. @@ -215,4 +231,72 @@ public static function queues() } return $queues; } + + /** + * Remove Items from the queue + * Safely moving each item to a temporary queue before processing it + * If the Job matches, counts otherwise puts it in a requeue_queue + * which at the end eventually be copied back into the original queue + * + * @private + * + * @param string $queue The name of the queue + * @param array $items + * @return integer number of deleted items + */ + private static function removeItems($queue, $items = Array()) + { + $counter = 0; + $originalQueue = 'queue:'. $queue; + $tempQueue = $originalQueue. ':temp:'. time(); + $requeueQueue = $tempQueue. ':requeue'; + + // move each item from original queue to temp queue and process it + $finished = false; + while(!$finished) { + $string = self::redis()->rpoplpush($originalQueue, self::redis()->getPrefix() . $tempQueue); + + if(!empty($string)) { + $decoded = json_decode($string, true); + if(in_array($decoded['class'], $items)) { + $counter++; + } else { + self::redis()->rpoplpush($tempQueue, self::redis()->getPrefix() . $requeueQueue); + } + } else { + $finished = true; + } + } + + // move back from temp queue to original queue + $finished = false; + while(!$finished) { + $string = self::redis()->rpoplpush($requeueQueue, self::redis()->getPrefix() .$originalQueue); + if (empty($string)) { + $finished = true; + } + } + + // remove temp queue and requeue queue + self::redis()->del($requeueQueue); + self::redis()->del($tempQueue); + + return $counter; + } + + /** + * Remove List + * + * @private + * + * @params string $queue the name of the queue + * @return integer number of deleted items belongs to this list + */ + private static function removeList($queue) + { + $counter = self::size($queue); + $result = self::redis()->del('queue:' . $queue); + return ($result == 1) ? $counter : 0; + } } + diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 574e085c..3d3848d2 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -78,6 +78,7 @@ class Resque_Redis 'zremrangebyscore', 'sort', 'rename' + 'rpoplpush' ); // sinterstore // sunion @@ -86,7 +87,6 @@ class Resque_Redis // sdiffstore // sinter // smove - // rpoplpush // mget // msetnx // mset diff --git a/test/Resque/Tests/JobTest.php b/test/Resque/Tests/JobTest.php index 0c096966..f3a6e997 100644 --- a/test/Resque/Tests/JobTest.php +++ b/test/Resque/Tests/JobTest.php @@ -180,4 +180,77 @@ public function testJobWithNamespace() Resque_Redis::prefix('resque'); $this->assertEquals(Resque::size($queue), 0); } -} \ No newline at end of file + + public function testDequeueAll() + { + $queue = 'jobs'; + Resque::enqueue($queue, 'Test_Job_Dequeue'); + Resque::enqueue($queue, 'Test_Job_Dequeue'); + $this->assertEquals(Resque::size($queue), 2); + $this->assertEquals(Resque::dequeue($queue), 2); + $this->assertEquals(Resque::size($queue), 0); + } + + public function testDequeueMakeSureNotDeleteOthers() + { + $queue = 'jobs'; + Resque::enqueue($queue, 'Test_Job_Dequeue'); + Resque::enqueue($queue, 'Test_Job_Dequeue'); + $other_queue = 'other_jobs'; + Resque::enqueue($other_queue, 'Test_Job_Dequeue'); + Resque::enqueue($other_queue, 'Test_Job_Dequeue'); + $this->assertEquals(Resque::size($queue), 2); + $this->assertEquals(Resque::size($other_queue), 2); + $this->assertEquals(Resque::dequeue($queue), 2); + $this->assertEquals(Resque::size($queue), 0); + $this->assertEquals(Resque::size($other_queue), 2); + } + + public function testDequeueSpecificItem() + { + $queue = 'jobs'; + Resque::enqueue($queue, 'Test_Job_Dequeue1'); + Resque::enqueue($queue, 'Test_Job_Dequeue2'); + $this->assertEquals(Resque::size($queue), 2); + $test = array('Test_Job_Dequeue2'); + $this->assertEquals(Resque::dequeue($queue, $test), 1); + $this->assertEquals(Resque::size($queue), 1); + } + + public function testDequeueSpecificMultipleItems() + { + $queue = 'jobs'; + Resque::enqueue($queue, 'Test_Job_Dequeue1'); + Resque::enqueue($queue, 'Test_Job_Dequeue2'); + Resque::enqueue($queue, 'Test_Job_Dequeue3'); + $this->assertEquals(Resque::size($queue), 3); + $test = array('Test_Job_Dequeue2', 'Test_Job_Dequeue3'); + $this->assertEquals(Resque::dequeue($queue, $test), 2); + $this->assertEquals(Resque::size($queue), 1); + } + + public function testDequeueNonExistingItem() + { + $queue = 'jobs'; + Resque::enqueue($queue, 'Test_Job_Dequeue1'); + Resque::enqueue($queue, 'Test_Job_Dequeue2'); + Resque::enqueue($queue, 'Test_Job_Dequeue3'); + $this->assertEquals(Resque::size($queue), 3); + $test = array('Test_Job_Dequeue4'); + $this->assertEquals(Resque::dequeue($queue, $test), 0); + $this->assertEquals(Resque::size($queue), 3); + } + + public function testDequeueNonExistingItem2() + { + $queue = 'jobs'; + Resque::enqueue($queue, 'Test_Job_Dequeue1'); + Resque::enqueue($queue, 'Test_Job_Dequeue2'); + Resque::enqueue($queue, 'Test_Job_Dequeue3'); + $this->assertEquals(Resque::size($queue), 3); + $test = array('Test_Job_Dequeue4', 'Test_Job_Dequeue1'); + $this->assertEquals(Resque::dequeue($queue, $test), 1); + $this->assertEquals(Resque::size($queue), 2); + } + +} From 29e37784cde74ff43841bda4ec7714dfa8173cfa Mon Sep 17 00:00:00 2001 From: Wedy Chainy Date: Sun, 21 Sep 2014 18:21:08 +1000 Subject: [PATCH 146/194] Alter dequeue - now accepting 'args' and "ID" arguments --- README.md | 11 +++++- lib/Resque.php | 40 ++++++++++++++++++- lib/Resque/Redis.php | 2 +- test/Resque/Tests/JobTest.php | 72 +++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3a1860d8..a254bc01 100644 --- a/README.md +++ b/README.md @@ -139,8 +139,17 @@ class My_Job This method can be used to conveniently remove a job from a queue. ```php -// Removes 'My_Job' of queue 'default' +// Removes job class 'My_Job' of queue 'default' Resque::dequeue('default', ['My_Job']); + +// Removes job class 'My_Job' with Job ID '087df5819a790ac666c9608e2234b21e' of queue 'default' +Resuque::dequeue('default', ['My_Job' => '087df5819a790ac666c9608e2234b21e']); + +// Removes job class 'My_Job' with arguments of queue 'default' +Resque::dequeue('default', ['My_Job' => array('foo' => 1, 'bar' => 2)]); + +// Removes multiple jobs +Resque::dequeue('default', ['My_Job', 'My_Job2']); ``` If no jobs are given, this method will dequeue all jobs matching the provided queue. diff --git a/lib/Resque.php b/lib/Resque.php index c83b6017..a26eaa63 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -257,8 +257,7 @@ private static function removeItems($queue, $items = Array()) $string = self::redis()->rpoplpush($originalQueue, self::redis()->getPrefix() . $tempQueue); if(!empty($string)) { - $decoded = json_decode($string, true); - if(in_array($decoded['class'], $items)) { + if(self::matchItem($string, $items)) { $counter++; } else { self::redis()->rpoplpush($tempQueue, self::redis()->getPrefix() . $requeueQueue); @@ -284,6 +283,43 @@ private static function removeItems($queue, $items = Array()) return $counter; } + /** + * matching item + * item can be ['class'] or ['class' => 'id'] or ['class' => {:foo => 1, :bar => 2}] + * @private + * + * @params string $string redis result in json + * @params $items + * + * @return (bool) + */ + private static function matchItem($string, $items) + { + $decoded = json_decode($string, true); + + foreach($items as $key => $val) { + # class name only ex: item[0] = ['class'] + if (is_numeric($key)) { + if($decoded['class'] == $val) { + return true; + } + # class name with args , example: item[0] = ['class' => {'foo' => 1, 'bar' => 2}] + } elseif (is_array($val)) { + $decodedArgs = (array)$decoded['args'][0]; + if ($decoded['class'] == $key && + count($decodedArgs) > 0 && count(array_diff($decodedArgs, $val)) == 0) { + return true; + } + # class name with ID, example: item[0] = ['class' => 'id'] + } else { + if ($decoded['class'] == $key && $decoded['id'] == $val) { + return true; + } + } + } + return false; + } + /** * Remove List * diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 3d3848d2..59ca215e 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -77,7 +77,7 @@ class Resque_Redis 'zscore', 'zremrangebyscore', 'sort', - 'rename' + 'rename', 'rpoplpush' ); // sinterstore diff --git a/test/Resque/Tests/JobTest.php b/test/Resque/Tests/JobTest.php index f3a6e997..d0faa539 100644 --- a/test/Resque/Tests/JobTest.php +++ b/test/Resque/Tests/JobTest.php @@ -253,4 +253,76 @@ public function testDequeueNonExistingItem2() $this->assertEquals(Resque::size($queue), 2); } + public function testDequeueItemID() + { + $queue = 'jobs'; + Resque::enqueue($queue, 'Test_Job_Dequeue'); + $qid = Resque::enqueue($queue, 'Test_Job_Dequeue'); + $this->assertEquals(Resque::size($queue), 2); + $test = array('Test_Job_Dequeue' => $qid); + $this->assertEquals(Resque::dequeue($queue, $test), 1); + $this->assertEquals(Resque::size($queue), 1); + } + + public function testDequeueWrongItemID() + { + $queue = 'jobs'; + Resque::enqueue($queue, 'Test_Job_Dequeue'); + $qid = Resque::enqueue($queue, 'Test_Job_Dequeue'); + $this->assertEquals(Resque::size($queue), 2); + #qid right but class name is wrong + $test = array('Test_Job_Dequeue1' => $qid); + $this->assertEquals(Resque::dequeue($queue, $test), 0); + $this->assertEquals(Resque::size($queue), 2); + } + + public function testDequeueWrongItemID2() + { + $queue = 'jobs'; + Resque::enqueue($queue, 'Test_Job_Dequeue'); + $qid = Resque::enqueue($queue, 'Test_Job_Dequeue'); + $this->assertEquals(Resque::size($queue), 2); + $test = array('Test_Job_Dequeue' => 'r4nD0mH4sh3dId'); + $this->assertEquals(Resque::dequeue($queue, $test), 0); + $this->assertEquals(Resque::size($queue), 2); + } + + public function testDequeueItemWithArg() + { + $queue = 'jobs'; + $arg = array('foo' => 1, 'bar' => 2); + Resque::enqueue($queue, 'Test_Job_Dequeue9'); + Resque::enqueue($queue, 'Test_Job_Dequeue9', $arg); + $this->assertEquals(Resque::size($queue), 2); + $test = array('Test_Job_Dequeue9' => $arg); + $this->assertEquals(Resque::dequeue($queue, $test), 1); + #$this->assertEquals(Resque::size($queue), 1); + } + + public function testDequeueItemWithUnorderedArg() + { + $queue = 'jobs'; + $arg = array('foo' => 1, 'bar' => 2); + $arg2 = array('bar' => 2, 'foo' => 1); + Resque::enqueue($queue, 'Test_Job_Dequeue'); + Resque::enqueue($queue, 'Test_Job_Dequeue', $arg); + $this->assertEquals(Resque::size($queue), 2); + $test = array('Test_Job_Dequeue' => $arg2); + $this->assertEquals(Resque::dequeue($queue, $test), 1); + $this->assertEquals(Resque::size($queue), 1); + } + + public function testDequeueItemWithiWrongArg() + { + $queue = 'jobs'; + $arg = array('foo' => 1, 'bar' => 2); + $arg2 = array('foo' => 2, 'bar' => 3); + Resque::enqueue($queue, 'Test_Job_Dequeue'); + Resque::enqueue($queue, 'Test_Job_Dequeue', $arg); + $this->assertEquals(Resque::size($queue), 2); + $test = array('Test_Job_Dequeue' => $arg2); + $this->assertEquals(Resque::dequeue($queue, $test), 0); + $this->assertEquals(Resque::size($queue), 2); + } + } From bc9dac71ca70a3910b42af9b57a8e332d80af944 Mon Sep 17 00:00:00 2001 From: vincent zhao Date: Thu, 25 Sep 2014 10:31:09 +1000 Subject: [PATCH 147/194] Allows a callable to be passed to Resque::setBackend for setting Resque:: --- lib/Resque.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index a26eaa63..6b067ae4 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -33,6 +33,8 @@ class Resque * the redis server that Resque will talk to. * * @param mixed $server Host/port combination separated by a colon, DSN-formatted URI, or + * a callable that receives the configured database ID + * and returns a Resque_Redis instance, or * a nested array of servers with host/port pairs. * @param int $database */ @@ -54,10 +56,15 @@ public static function redis() return self::$redis; } - self::$redis = new Resque_Redis(self::$redisServer, self::$redisDatabase); + if (is_callable(self::$redisServer)) { + self::$redis = call_user_func(self::$redisServer, self::$redisDatabase); + } else { + self::$redis = new Resque_Redis(self::$redisServer, self::$redisDatabase); + } + return self::$redis; } - + /** * fork() helper method for php-resque that handles issues PHP socket * and phpredis have with passing around sockets between child/parent @@ -135,7 +142,7 @@ public static function dequeue($queue, $items = Array()) return self::removeList($queue); } } - + /** * Pop an item off the end of the specified queues, using blocking list pop, * decode it and return it. @@ -324,7 +331,7 @@ private static function matchItem($string, $items) * Remove List * * @private - * + * * @params string $queue the name of the queue * @return integer number of deleted items belongs to this list */ From 2c8b215cda2beb50197b9527c3b0980c9e4f6505 Mon Sep 17 00:00:00 2001 From: Dayson Pais Date: Sat, 8 Nov 2014 15:11:20 +0530 Subject: [PATCH 148/194] Implicitly type cast exception while logging. Removed the unnecessary (string) type-casting. --- lib/Resque/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 2d6f6494..750c41c9 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -241,7 +241,7 @@ public function perform(Resque_Job $job) $job->perform(); } catch(Exception $e) { - $this->logger->log(Psr\Log\LogLevel::CRITICAL, '{job} has failed {stack}', array('job' => $job, 'stack' => (string)$e)); + $this->logger->log(Psr\Log\LogLevel::CRITICAL, '{job} has failed {stack}', array('job' => $job, 'stack' => $e)); $job->fail($e); return; } From 226ec33bb0bcef1595c5e560454e687c1130b5ed Mon Sep 17 00:00:00 2001 From: "Axel K." Date: Mon, 10 Nov 2014 15:33:42 +0100 Subject: [PATCH 149/194] Test for asserting that correct items get dequeued when args are provided --- test/Resque/Tests/JobTest.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/Resque/Tests/JobTest.php b/test/Resque/Tests/JobTest.php index d0faa539..0636d8bf 100644 --- a/test/Resque/Tests/JobTest.php +++ b/test/Resque/Tests/JobTest.php @@ -298,6 +298,29 @@ public function testDequeueItemWithArg() $this->assertEquals(Resque::dequeue($queue, $test), 1); #$this->assertEquals(Resque::size($queue), 1); } + + public function testDequeueSeveralItemsWithArgs() + { + // GIVEN + $queue = 'jobs'; + $args = array('foo' => 1, 'bar' => 10); + $removeArgs = array('foo' => 1, 'bar' => 2); + Resque::enqueue($queue, 'Test_Job_Dequeue9', $args); + Resque::enqueue($queue, 'Test_Job_Dequeue9', $removeArgs); + Resque::enqueue($queue, 'Test_Job_Dequeue9', $removeArgs); + $this->assertEquals(Resque::size($queue), 3); + + // WHEN + $test = array('Test_Job_Dequeue9' => $removeArgs); + $removedItems = Resque::dequeue($queue, $test); + + // THEN + $this->assertEquals($removedItems, 2); + $this->assertEquals(Resque::size($queue), 1); + $item = Resque::pop($queue); + $this->assertInternalType('array', $item['args']); + $this->assertEquals(10, $item['args'][0]['bar'], 'Wrong items were dequeued from queue!'); + } public function testDequeueItemWithUnorderedArg() { From 6cda08de2570b9a4ba67157c3d296857e2bf0ab1 Mon Sep 17 00:00:00 2001 From: "Axel K." Date: Mon, 10 Nov 2014 15:38:58 +0100 Subject: [PATCH 150/194] #218 Remove item from queue as well when args match --- lib/Resque.php | 63 +++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index 6b067ae4..0b621bf5 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -253,41 +253,42 @@ public static function queues() */ private static function removeItems($queue, $items = Array()) { - $counter = 0; - $originalQueue = 'queue:'. $queue; - $tempQueue = $originalQueue. ':temp:'. time(); - $requeueQueue = $tempQueue. ':requeue'; - - // move each item from original queue to temp queue and process it - $finished = false; - while(!$finished) { - $string = self::redis()->rpoplpush($originalQueue, self::redis()->getPrefix() . $tempQueue); - - if(!empty($string)) { - if(self::matchItem($string, $items)) { - $counter++; - } else { - self::redis()->rpoplpush($tempQueue, self::redis()->getPrefix() . $requeueQueue); - } - } else { - $finished = true; + $counter = 0; + $originalQueue = 'queue:'. $queue; + $tempQueue = $originalQueue. ':temp:'. time(); + $requeueQueue = $tempQueue. ':requeue'; + + // move each item from original queue to temp queue and process it + $finished = false; + while (!$finished) { + $string = self::redis()->rpoplpush($originalQueue, self::redis()->getPrefix() . $tempQueue); + + if (!empty($string)) { + if(self::matchItem($string, $items)) { + self::redis()->rpop($tempQueue); + $counter++; + } else { + self::redis()->rpoplpush($tempQueue, self::redis()->getPrefix() . $requeueQueue); + } + } else { + $finished = true; + } } - } - // move back from temp queue to original queue - $finished = false; - while(!$finished) { - $string = self::redis()->rpoplpush($requeueQueue, self::redis()->getPrefix() .$originalQueue); - if (empty($string)) { - $finished = true; + // move back from temp queue to original queue + $finished = false; + while (!$finished) { + $string = self::redis()->rpoplpush($requeueQueue, self::redis()->getPrefix() .$originalQueue); + if (empty($string)) { + $finished = true; + } } - } - - // remove temp queue and requeue queue - self::redis()->del($requeueQueue); - self::redis()->del($tempQueue); - return $counter; + // remove temp queue and requeue queue + self::redis()->del($requeueQueue); + self::redis()->del($tempQueue); + + return $counter; } /** From 7101a3097f95ddb8d1d23c09585a7610fece1277 Mon Sep 17 00:00:00 2001 From: Andrew Brereton Date: Thu, 18 Dec 2014 17:27:18 +1100 Subject: [PATCH 151/194] gethostname() doesn't work on Amazon's EC2 --- lib/Resque/Worker.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 379b853e..d392b238 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -69,13 +69,8 @@ public function __construct($queues) } $this->queues = $queues; - if(function_exists('gethostname')) { - $hostname = gethostname(); - } - else { - $hostname = php_uname('n'); - } - $this->hostname = $hostname; + $this->hostname = php_uname('n'); + $this->id = $this->hostname . ':'.getmypid() . ':' . implode(',', $this->queues); } From a95c24b32e31218ee8efe7de09e6cad60c23eeb2 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Thu, 18 Sep 2014 23:20:04 +1000 Subject: [PATCH 152/194] add beforeEnqueue hook that allows the enqueue to be cancelled --- README.md | 12 ++++++ lib/Resque.php | 35 ++++++++++++----- lib/Resque/Job.php | 7 +++- lib/Resque/Job/DontCreate.php | 12 ++++++ test/Resque/Tests/EventTest.php | 69 ++++++++++++++++++++++++--------- 5 files changed, 106 insertions(+), 29 deletions(-) create mode 100644 lib/Resque/Job/DontCreate.php diff --git a/README.md b/README.md index a254bc01..4a969205 100644 --- a/README.md +++ b/README.md @@ -413,6 +413,18 @@ Called whenever a job fails. Arguments passed (in this order) include: * Exception - The exception that was thrown when the job failed * Resque_Job - The job that failed +#### beforeEnqueue #### + +Called immediately before a job is enqueued using the `Resque::enqueue` method. +Arguments passed (in this order) include: + +* Class - string containing the name of the job to be enqueued +* Arguments - array of arguments for the job +* Queue - string containing the name of the queue the job is to be enqueued in +* ID - string containing the token of the job to be enqueued + +You can prevent enqueing of the job by throwing an exception of `Resque_Job_DontCreate`. + #### afterEnqueue #### Called after a job has been queued using the `Resque::enqueue` method. Arguments passed diff --git a/lib/Resque.php b/lib/Resque.php index 6b067ae4..908b63ec 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -201,17 +201,24 @@ public static function size($queue) */ public static function enqueue($queue, $class, $args = null, $trackStatus = false) { - $result = Resque_Job::create($queue, $class, $args, $trackStatus); - if ($result) { - Resque_Event::trigger('afterEnqueue', array( - 'class' => $class, - 'args' => $args, - 'queue' => $queue, - 'id' => $result, - )); + $id = Resque::generateJobId(); + $hookParams = array( + 'class' => $class, + 'args' => $args, + 'queue' => $queue, + 'id' => $id, + ); + try { + Resque_Event::trigger('beforeEnqueue', $hookParams); } + catch(Resque_Job_DontCreate $e) { + return $id; + } + + Resque_Job::create($queue, $class, $args, $trackStatus, $id); + Resque_Event::trigger('afterEnqueue', $hookParams); - return $result; + return $id; } /** @@ -341,5 +348,15 @@ private static function removeList($queue) $result = self::redis()->del('queue:' . $queue); return ($result == 1) ? $counter : 0; } + + /* + * Generate an identifier to attach to a job for status tracking. + * + * @return string + */ + public static function generateJobId() + { + return md5(uniqid('', true)); + } } diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index ca21445a..1eb8fdb2 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -50,14 +50,17 @@ public function __construct($queue, $payload) * * @return string */ - public static function create($queue, $class, $args = null, $monitor = false) + public static function create($queue, $class, $args = null, $monitor = false, $id = null) { + if (is_null($id)) { + $id = Resque::generateJobId(); + } + if($args !== null && !is_array($args)) { throw new InvalidArgumentException( 'Supplied $args must be an array.' ); } - $id = md5(uniqid('', true)); Resque::push($queue, array( 'class' => $class, 'args' => array($args), diff --git a/lib/Resque/Job/DontCreate.php b/lib/Resque/Job/DontCreate.php new file mode 100644 index 00000000..31c33cdc --- /dev/null +++ b/lib/Resque/Job/DontCreate.php @@ -0,0 +1,12 @@ + + * @license http://www.opensource.org/licenses/mit-license.php + */ +class Resque_Job_DontCreate extends Exception +{ + +} \ No newline at end of file diff --git a/test/Resque/Tests/EventTest.php b/test/Resque/Tests/EventTest.php index 894fd7a9..44f31b18 100644 --- a/test/Resque/Tests/EventTest.php +++ b/test/Resque/Tests/EventTest.php @@ -9,11 +9,11 @@ class Resque_Tests_EventTest extends Resque_Tests_TestCase { private $callbacksHit = array(); - + public function setUp() { Test_Job::$called = false; - + // Register a worker to test with $this->worker = new Resque_Worker('jobs'); $this->worker->setLogger(new Resque_Log()); @@ -38,7 +38,7 @@ public function getEventTestJob() $job->worker = $this->worker; return $job; } - + public function eventCallbackProvider() { return array( @@ -47,7 +47,7 @@ public function eventCallbackProvider() array('afterFork', 'afterForkEventCallback'), ); } - + /** * @dataProvider eventCallbackProvider */ @@ -58,10 +58,10 @@ public function testEventCallbacksFire($event, $callback) $job = $this->getEventTestJob(); $this->worker->perform($job); $this->worker->work(0); - + $this->assertContains($callback, $this->callbacksHit, $event . ' callback (' . $callback .') was not called'); } - + public function testBeforeForkEventCallbackFires() { $event = 'beforeFork'; @@ -76,6 +76,18 @@ public function testBeforeForkEventCallbackFires() $this->assertContains($callback, $this->callbacksHit, $event . ' callback (' . $callback .') was not called'); } + public function testBeforeEnqueueEventCallbackFires() + { + $event = 'beforeEnqueue'; + $callback = 'beforeEnqueueEventCallback'; + + Resque_Event::listen($event, array($this, $callback)); + Resque::enqueue('jobs', 'Test_Job', array( + 'somevar' + )); + $this->assertContains($callback, $this->callbacksHit, $event . ' callback (' . $callback .') was not called'); + } + public function testBeforePerformEventCanStopWork() { $callback = 'beforePerformEventDontPerformCallback'; @@ -87,23 +99,34 @@ public function testBeforePerformEventCanStopWork() $this->assertContains($callback, $this->callbacksHit, $callback . ' callback was not called'); $this->assertFalse(Test_Job::$called, 'Job was still performed though Resque_Job_DontPerform was thrown'); } - + + public function testBeforeEnqueueEventStopsJobCreation() + { + $callback = 'beforeEnqueueEventDontCreateCallback'; + Resque_Event::listen('beforeEnqueue', array($this, $callback)); + Resque_Event::listen('afterEnqueue', array($this, 'afterEnqueueEventCallback')); + + Resque::enqueue('test_job', 'TestClass'); + $this->assertContains($callback, $this->callbacksHit, $callback . ' callback was not called'); + $this->assertNotContains('afterEnqueueEventCallback', $this->callbacksHit, 'afterEnqueue was still called, even though it should not have been'); + } + public function testAfterEnqueueEventCallbackFires() { $callback = 'afterEnqueueEventCallback'; - $event = 'afterEnqueue'; - + $event = 'afterEnqueue'; + Resque_Event::listen($event, array($this, $callback)); Resque::enqueue('jobs', 'Test_Job', array( 'somevar' - )); + )); $this->assertContains($callback, $this->callbacksHit, $event . ' callback (' . $callback .') was not called'); } public function testStopListeningRemovesListener() { $callback = 'beforePerformEventCallback'; - $event = 'beforePerform'; + $event = 'beforePerform'; Resque_Event::listen($event, array($this, $callback)); Resque_Event::stopListening($event, array($this, $callback)); @@ -112,18 +135,23 @@ public function testStopListeningRemovesListener() $this->worker->perform($job); $this->worker->work(0); - $this->assertNotContains($callback, $this->callbacksHit, + $this->assertNotContains($callback, $this->callbacksHit, $event . ' callback (' . $callback .') was called though Resque_Event::stopListening was called' ); } - public function beforePerformEventDontPerformCallback($instance) { $this->callbacksHit[] = __FUNCTION__; throw new Resque_Job_DontPerform; } - + + public function beforeEnqueueEventDontCreateCallback($queue, $class, $args, $track = false) + { + $this->callbacksHit[] = __FUNCTION__; + throw new Resque_Job_DontCreate; + } + public function assertValidEventCallback($function, $job) { $this->callbacksHit[] = $function; @@ -133,7 +161,7 @@ public function assertValidEventCallback($function, $job) $args = $job->getArguments(); $this->assertEquals($args[0], 'somevar'); } - + public function afterEnqueueEventCallback($class, $args) { $this->callbacksHit[] = __FUNCTION__; @@ -142,12 +170,17 @@ public function afterEnqueueEventCallback($class, $args) 'somevar', ), $args); } - + + public function beforeEnqueueEventCallback($job) + { + $this->callbacksHit[] = __FUNCTION__; + } + public function beforePerformEventCallback($job) { $this->assertValidEventCallback(__FUNCTION__, $job); } - + public function afterPerformEventCallback($job) { $this->assertValidEventCallback(__FUNCTION__, $job); @@ -157,7 +190,7 @@ public function beforeForkEventCallback($job) { $this->assertValidEventCallback(__FUNCTION__, $job); } - + public function afterForkEventCallback($job) { $this->assertValidEventCallback(__FUNCTION__, $job); From e815c687f169addcb023ae108fee939eef9fb300 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Thu, 18 Sep 2014 23:20:45 +1000 Subject: [PATCH 153/194] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a77d5beb..d3ceb190 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ Changes by iskandar introduce improved support for using DSNs to connect to Redi * Fix an issue where a lost connection to Redis could cause an infinite loop (atorres757) * Add a helper method to `Resque_Redis` to remove the namespace applied to Redis keys (tonypiper) * Call beforePerform hook before retrieivng an instance of the job class (allows beforePerform to cancel a job with DontPerform before initialising your application) +* Add `beforeEnqueue` hook, called before a job is placed on a queue ## 1.2 (2012-10-13) ## From 2308c3ced47ebecdfcb698332d837812f6942c59 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Thu, 18 Sep 2014 23:26:59 +1000 Subject: [PATCH 154/194] update phpdoc --- lib/Resque/Job.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 1eb8fdb2..344c6c14 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -47,6 +47,7 @@ public function __construct($queue, $payload) * @param string $class The name of the class that contains the code to execute the job. * @param array $args Any optional arguments that should be passed when the job is executed. * @param boolean $monitor Set to true to be able to monitor the status of a job. + * @param string $id Unique identifier for tracking the job. Generated if not supplied. * * @return string */ From 800770522110af8b220c92ca7b2c3fcb425ec745 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Mon, 2 Feb 2015 12:27:28 -0800 Subject: [PATCH 155/194] return false when job creation is cancelled by beforeEnqueue --- lib/Resque.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index 908b63ec..db7d4f82 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -197,7 +197,7 @@ public static function size($queue) * @param array $args Any optional arguments that should be passed when the job is executed. * @param boolean $trackStatus Set to true to be able to monitor the status of a job. * - * @return string + * @return string|boolean Job ID when the job was created, false if creation was cancelled due to beforeEnqueue */ public static function enqueue($queue, $class, $args = null, $trackStatus = false) { @@ -212,7 +212,7 @@ public static function enqueue($queue, $class, $args = null, $trackStatus = fals Resque_Event::trigger('beforeEnqueue', $hookParams); } catch(Resque_Job_DontCreate $e) { - return $id; + return false; } Resque_Job::create($queue, $class, $args, $trackStatus, $id); From 0c39e2ca7ae5cbc2f6b40c2d90e7ffcf3ab23abf Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Mon, 2 Feb 2015 12:30:40 -0800 Subject: [PATCH 156/194] ensure false is returned when DontCreate is thrown --- test/Resque/Tests/EventTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/Resque/Tests/EventTest.php b/test/Resque/Tests/EventTest.php index 44f31b18..1147c991 100644 --- a/test/Resque/Tests/EventTest.php +++ b/test/Resque/Tests/EventTest.php @@ -106,9 +106,10 @@ public function testBeforeEnqueueEventStopsJobCreation() Resque_Event::listen('beforeEnqueue', array($this, $callback)); Resque_Event::listen('afterEnqueue', array($this, 'afterEnqueueEventCallback')); - Resque::enqueue('test_job', 'TestClass'); + $result = Resque::enqueue('test_job', 'TestClass'); $this->assertContains($callback, $this->callbacksHit, $callback . ' callback was not called'); $this->assertNotContains('afterEnqueueEventCallback', $this->callbacksHit, 'afterEnqueue was still called, even though it should not have been'); + $this->assertFalse($result); } public function testAfterEnqueueEventCallbackFires() From 5aed917f72aab5ccb9f948ed40f99c9b8e2a02d6 Mon Sep 17 00:00:00 2001 From: Magnus Persson Date: Wed, 11 Mar 2015 23:41:12 +0100 Subject: [PATCH 157/194] Resolves chrisboulton/php-resque#145 --- lib/Resque/Redis.php | 2 +- test/Resque/Tests/JobTest.php | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 59ca215e..5410499d 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -98,7 +98,7 @@ class Resque_Redis */ public static function prefix($namespace) { - if (strpos($namespace, ':') === false) { + if (substr($namespace, -1) !== ':') { $namespace .= ':'; } self::$defaultNamespace = $namespace; diff --git a/test/Resque/Tests/JobTest.php b/test/Resque/Tests/JobTest.php index 0636d8bf..156ec04f 100644 --- a/test/Resque/Tests/JobTest.php +++ b/test/Resque/Tests/JobTest.php @@ -166,7 +166,21 @@ public function testJobWithTearDownCallbackFiresTearDown() $this->assertTrue(Test_Job_With_TearDown::$called); } - + + public function testNamespaceNaming() { + $fixture = array( + array('test' => 'more:than:one:with:', 'assertValue' => 'more:than:one:with:'), + array('test' => 'more:than:one:without', 'assertValue' => 'more:than:one:without:'), + array('test' => 'resque', 'assertValue' => 'resque:'), + array('test' => 'resque:', 'assertValue' => 'resque:'), + ); + + foreach($fixture as $item) { + Resque_Redis::prefix($item['test']); + $this->assertEquals(Resque_Redis::getPrefix(), $item['assertValue']); + } + } + public function testJobWithNamespace() { Resque_Redis::prefix('php'); @@ -176,7 +190,7 @@ public function testJobWithNamespace() $this->assertEquals(Resque::queues(), array('jobs')); $this->assertEquals(Resque::size($queue), 1); - + Resque_Redis::prefix('resque'); $this->assertEquals(Resque::size($queue), 0); } From f29e09d68b18fa22296f78ed2a5c9276a80e3381 Mon Sep 17 00:00:00 2001 From: Dan Rahmel Date: Fri, 13 Mar 2015 14:49:30 -0700 Subject: [PATCH 158/194] Added remove_queue command from Resque --- lib/Resque.php | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index efe7f257..09e01669 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -143,6 +143,19 @@ public static function dequeue($queue, $items = Array()) } } + /** + * Remove specified queue + * + * @param string $queue The name of the queue to remove. + * @return integer number of deleted items + */ + public static function removeQueue($queue) + { + $num = self::removeList($queue); + self::redis()->srem('queues', $queue); + return $num; + } + /** * Pop an item off the end of the specified queues, using blocking list pop, * decode it and return it. @@ -264,12 +277,12 @@ private static function removeItems($queue, $items = Array()) $originalQueue = 'queue:'. $queue; $tempQueue = $originalQueue. ':temp:'. time(); $requeueQueue = $tempQueue. ':requeue'; - + // move each item from original queue to temp queue and process it $finished = false; while (!$finished) { $string = self::redis()->rpoplpush($originalQueue, self::redis()->getPrefix() . $tempQueue); - + if (!empty($string)) { if(self::matchItem($string, $items)) { self::redis()->rpop($tempQueue); @@ -294,7 +307,7 @@ private static function removeItems($queue, $items = Array()) // remove temp queue and requeue queue self::redis()->del($requeueQueue); self::redis()->del($tempQueue); - + return $counter; } From 44940e84bc93adda75f52ea644d00db461ae9a63 Mon Sep 17 00:00:00 2001 From: Dan Rahmel Date: Fri, 13 Mar 2015 15:36:24 -0700 Subject: [PATCH 159/194] Restored whitespace --- lib/Resque.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index 09e01669..47291899 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -147,7 +147,7 @@ public static function dequeue($queue, $items = Array()) * Remove specified queue * * @param string $queue The name of the queue to remove. - * @return integer number of deleted items + * @return integer Number of deleted items */ public static function removeQueue($queue) { @@ -277,12 +277,12 @@ private static function removeItems($queue, $items = Array()) $originalQueue = 'queue:'. $queue; $tempQueue = $originalQueue. ':temp:'. time(); $requeueQueue = $tempQueue. ':requeue'; - + // move each item from original queue to temp queue and process it $finished = false; while (!$finished) { $string = self::redis()->rpoplpush($originalQueue, self::redis()->getPrefix() . $tempQueue); - + if (!empty($string)) { if(self::matchItem($string, $items)) { self::redis()->rpop($tempQueue); @@ -307,7 +307,7 @@ private static function removeItems($queue, $items = Array()) // remove temp queue and requeue queue self::redis()->del($requeueQueue); self::redis()->del($tempQueue); - + return $counter; } From 570e4a9e5551f5f6db3a5d9f63cc9a3dc08748ed Mon Sep 17 00:00:00 2001 From: Matthew Turland Date: Tue, 12 May 2015 15:07:20 -0500 Subject: [PATCH 160/194] Corrected type in Resque_Job::$payload docblock The docblock for the $payload property in the Resque_Job class is object, which is inconsistent with the array type used for the corresponding constructor parameter. Other usage of the $payload property, such as in updateStatus(), indicate that array seems to be correct. --- lib/Resque/Job.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 344c6c14..07df07c7 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -19,7 +19,7 @@ class Resque_Job public $worker; /** - * @var object Object containing details of the job. + * @var array Array containing details of the job. */ public $payload; From 9c20e44483b3915a06106c32fc4db2d6dc58b40d Mon Sep 17 00:00:00 2001 From: Takuya Sato Date: Wed, 26 Aug 2015 10:26:48 +0900 Subject: [PATCH 161/194] return false if `json_encode()` failed. --- lib/Resque.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Resque.php b/lib/Resque.php index 47291899..5d933750 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -101,8 +101,12 @@ public static function fork() */ public static function push($queue, $item) { + $encodedItem = json_encode($item); + if ($encodedItem === false) { + return false; + } self::redis()->sadd('queues', $queue); - $length = self::redis()->rpush('queue:' . $queue, json_encode($item)); + $length = self::redis()->rpush('queue:' . $queue, $encodedItem); if ($length < 1) { return false; } From 0d5cff54ad7b48ed953ffb173c50bf92f1c07ff1 Mon Sep 17 00:00:00 2001 From: Rolf Vreijdenberger Date: Tue, 26 Jan 2016 14:54:02 +0100 Subject: [PATCH 162/194] should be able to use maxConnectRetries - be able to specify max_connect_retries in the dsn string as part of the query string --- lib/Resque/Redis.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 5410499d..e588dede 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -122,8 +122,10 @@ public function __construct($server, $database = null) // Look for known Credis_Client options $timeout = isset($options['timeout']) ? intval($options['timeout']) : null; $persistent = isset($options['persistent']) ? $options['persistent'] : ''; + $maxRetries = isset($options['max_connect_retries']) ? $options['max_connect_retries'] : 0; $this->driver = new Credis_Client($host, $port, $timeout, $persistent); + $this->driver->setMaxConnectRetries($maxRetries); if ($password){ $this->driver->auth($password); } From b3b1d408e54ec344bc1e8a0426c28bb409925c33 Mon Sep 17 00:00:00 2001 From: Bjoern Boschman Date: Tue, 8 Mar 2016 12:19:05 +0100 Subject: [PATCH 163/194] removed all closing PHP tags --- lib/Resque/Exception.php | 1 - lib/Resque/Failure/Interface.php | 1 - lib/Resque/Failure/Redis.php | 1 - lib/Resque/Job.php | 1 - lib/Resque/Job/Status.php | 1 - lib/Resque/Worker.php | 1 - 6 files changed, 6 deletions(-) diff --git a/lib/Resque/Exception.php b/lib/Resque/Exception.php index 60cca86f..01217c38 100644 --- a/lib/Resque/Exception.php +++ b/lib/Resque/Exception.php @@ -9,4 +9,3 @@ class Resque_Exception extends Exception { } -?> \ No newline at end of file diff --git a/lib/Resque/Failure/Interface.php b/lib/Resque/Failure/Interface.php index b7e5bc83..74de9e7b 100644 --- a/lib/Resque/Failure/Interface.php +++ b/lib/Resque/Failure/Interface.php @@ -18,4 +18,3 @@ interface Resque_Failure_Interface */ public function __construct($payload, $exception, $worker, $queue); } -?> \ No newline at end of file diff --git a/lib/Resque/Failure/Redis.php b/lib/Resque/Failure/Redis.php index cfac5b6c..69d68724 100644 --- a/lib/Resque/Failure/Redis.php +++ b/lib/Resque/Failure/Redis.php @@ -31,4 +31,3 @@ public function __construct($payload, $exception, $worker, $queue) Resque::redis()->rpush('failed', $data); } } -?> \ No newline at end of file diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 07df07c7..dfd88692 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -273,4 +273,3 @@ public function __toString() return '(' . implode(' | ', $name) . ')'; } } -?> diff --git a/lib/Resque/Job/Status.php b/lib/Resque/Job/Status.php index ffa351ba..00fc40c5 100644 --- a/lib/Resque/Job/Status.php +++ b/lib/Resque/Job/Status.php @@ -140,4 +140,3 @@ public function __toString() return 'job:' . $this->id . ':status'; } } -?> \ No newline at end of file diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 379b853e..0ba86d9a 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -564,4 +564,3 @@ public function setLogger(Psr\Log\LoggerInterface $logger) $this->logger = $logger; } } -?> From c08b6f64b794c018b0a028501bde8fea9594ae0e Mon Sep 17 00:00:00 2001 From: "Jonathan A. Schweder" Date: Tue, 15 Mar 2016 08:20:43 -0300 Subject: [PATCH 164/194] apply best practice in phpunit.xml file --- .gitignore | 1 + phpunit.xml => phpunit.xml.dist | 0 2 files changed, 1 insertion(+) rename phpunit.xml => phpunit.xml.dist (100%) diff --git a/.gitignore b/.gitignore index a47ff2d2..a793d958 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ vendor/ *.swp +phpunit.xml diff --git a/phpunit.xml b/phpunit.xml.dist similarity index 100% rename from phpunit.xml rename to phpunit.xml.dist From 47d3c9cbb20a1f7bd1d5b0e0d9c4c93654bd6a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Andr=C3=A9=20Schweder?= Date: Wed, 16 Mar 2016 08:09:34 -0300 Subject: [PATCH 165/194] add PHP 7 and HHVM to TravisCI runtime --- .travis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.travis.yml b/.travis.yml index cf099782..46d39196 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,17 @@ php: - 5.4 - 5.5 - 5.6 + - 7.0 + - hhvm + +matrix: + allow_failures: + - php: hhvm + - php: 7.0 env: - REDIS_STANDALONE=0 - REDIS_STANDALONE=1 + before_script: - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then wget https://github.com/nicolasff/phpredis/archive/2.2.3.zip -O php-redis.zip && unzip php-redis.zip; fi" - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then cd phpredis-2.2.3/ && phpize && ./configure && make && make install; fi" From e4cfc541c98c286e1e6934ef98a81bfdad5a2502 Mon Sep 17 00:00:00 2001 From: Luis Hdez Date: Wed, 30 Mar 2016 03:14:15 +0200 Subject: [PATCH 166/194] Fix CS whitespaces --- lib/Resque/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 0ba86d9a..6c72a367 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -63,7 +63,7 @@ class Resque_Worker public function __construct($queues) { $this->logger = new Resque_Log(); - + if(!is_array($queues)) { $queues = array($queues); } From 70102f1b89f3628f8aff4b73cb58ebf6d2107d92 Mon Sep 17 00:00:00 2001 From: Luis Hdez Date: Wed, 30 Mar 2016 03:15:01 +0200 Subject: [PATCH 167/194] Add control for OS X and cli_set_process_title --- lib/Resque/Worker.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 6c72a367..973d7fdc 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -327,7 +327,7 @@ private function startup() private function updateProcLine($status) { $processTitle = 'resque-' . Resque::VERSION . ': ' . $status; - if(function_exists('cli_set_process_title')) { + if(function_exists('cli_set_process_title') && PHP_OS !== 'Darwin') { cli_set_process_title($processTitle); } else if(function_exists('setproctitle')) { From 781483bc83d66582400e825eed49d83b3ccd9ec6 Mon Sep 17 00:00:00 2001 From: dewei Date: Wed, 13 Apr 2016 09:26:04 +0800 Subject: [PATCH 168/194] =?UTF-8?q?fixed=20=E2=80=98../bin/resque.php?= =?UTF-8?q?=E2=80=99=20to=20'../bin/resque'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo/resque.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/resque.php b/demo/resque.php index 3dfa5a9d..fcfe578b 100644 --- a/demo/resque.php +++ b/demo/resque.php @@ -4,4 +4,4 @@ require 'job.php'; require 'php_error_job.php'; -require '../bin/resque.php'; \ No newline at end of file +require '../bin/resque'; \ No newline at end of file From 16f88a6a38541a8793d9dd35ddce6e6c0f79ab92 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Wed, 3 Aug 2016 17:07:52 +0200 Subject: [PATCH 169/194] Move declare(ticks = 1) to startup Having declare(ticks = 1) inside registerSigHandlers() worked perfectly on PHP 5.6 but it doesn't on PHP 7. I found it that moving the declare(ticks = 1) outside registerSigHandlers() solves the issue. --- lib/Resque/Worker.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index 973d7fdc..cd960620 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -311,6 +311,8 @@ public function queues($fetch = true) */ private function startup() { + declare(ticks = 1); + $this->registerSigHandlers(); $this->pruneDeadWorkers(); Resque_Event::trigger('beforeFirstFork', $this); @@ -349,7 +351,6 @@ private function registerSigHandlers() return; } - declare(ticks = 1); pcntl_signal(SIGTERM, array($this, 'shutDownNow')); pcntl_signal(SIGINT, array($this, 'shutDownNow')); pcntl_signal(SIGQUIT, array($this, 'shutdown')); From 91caca7921b52000d2c49b3a3bec4a3d35774984 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Wed, 3 Aug 2016 20:40:30 +0200 Subject: [PATCH 170/194] Move declare(ticks = 1) to top --- lib/Resque/Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Resque/Worker.php b/lib/Resque/Worker.php index cd960620..94e0e280 100644 --- a/lib/Resque/Worker.php +++ b/lib/Resque/Worker.php @@ -1,4 +1,6 @@ registerSigHandlers(); $this->pruneDeadWorkers(); Resque_Event::trigger('beforeFirstFork', $this); From 2d6f29f6378134901d34935ed22e66921368b123 Mon Sep 17 00:00:00 2001 From: Jimmy Chandra Date: Tue, 9 Aug 2016 20:13:21 +0700 Subject: [PATCH 171/194] Fix typo in readme file --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a969205..c4da4ba4 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ This method can be used to conveniently remove a job from a queue. Resque::dequeue('default', ['My_Job']); // Removes job class 'My_Job' with Job ID '087df5819a790ac666c9608e2234b21e' of queue 'default' -Resuque::dequeue('default', ['My_Job' => '087df5819a790ac666c9608e2234b21e']); +Resque::dequeue('default', ['My_Job' => '087df5819a790ac666c9608e2234b21e']); // Removes job class 'My_Job' with arguments of queue 'default' Resque::dequeue('default', ['My_Job' => array('foo' => 1, 'bar' => 2)]); From 4b85638ccfb58e41a5635e16ce0868e58bbc4759 Mon Sep 17 00:00:00 2001 From: lauripiisang Date: Mon, 15 Aug 2016 16:33:18 +0300 Subject: [PATCH 172/194] Add support for unprotected unix socket - You can now provide a unix socket based redis connection: - `Resque::setBackend('unix:///path/to/redis.sock')` - username/password/db in unix socket dsn currently unsupported: - This middle layer for Dsn parsing seemed too clunky for me to introduce user/pass/db parsing for unix sockets. --- lib/Resque/Redis.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index e588dede..28051275 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -148,6 +148,7 @@ public function __construct($server, $database = null) * - host:port * - redis://user:pass@host:port/db?option1=val1&option2=val2 * - tcp://user:pass@host:port/db?option1=val1&option2=val2 + * - unix:///path/to/redis.sock * * Note: the 'user' part of the DSN is not used. * @@ -161,6 +162,16 @@ public static function parseDsn($dsn) // Use a sensible default for an empty DNS string $dsn = 'redis://' . self::DEFAULT_HOST; } + if(substr($dsn, 0, 7) === 'unix://') { + return array( + $dsn, + null, + null, + null, + null, + null, + ); + } $parts = parse_url(http://github.com/$dsn); // Check the URI scheme From 4dbdda6aa205aac6683b2f4a0e276ea2746f9696 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Mon, 15 Aug 2016 19:01:32 -0700 Subject: [PATCH 173/194] return false if the fork function is unavailable --- lib/Resque.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/Resque.php b/lib/Resque.php index 5d933750..d03b2ecf 100644 --- a/lib/Resque.php +++ b/lib/Resque.php @@ -72,12 +72,12 @@ public static function redis() * * Will close connection to Redis before forking. * - * @return int Return vars as per pcntl_fork() + * @return int Return vars as per pcntl_fork(). False if pcntl_fork is unavailable */ public static function fork() { if(!function_exists('pcntl_fork')) { - return -1; + return false; } // Close the connection to Redis before forking. @@ -281,12 +281,12 @@ private static function removeItems($queue, $items = Array()) $originalQueue = 'queue:'. $queue; $tempQueue = $originalQueue. ':temp:'. time(); $requeueQueue = $tempQueue. ':requeue'; - + // move each item from original queue to temp queue and process it $finished = false; while (!$finished) { $string = self::redis()->rpoplpush($originalQueue, self::redis()->getPrefix() . $tempQueue); - + if (!empty($string)) { if(self::matchItem($string, $items)) { self::redis()->rpop($tempQueue); @@ -311,7 +311,7 @@ private static function removeItems($queue, $items = Array()) // remove temp queue and requeue queue self::redis()->del($requeueQueue); self::redis()->del($tempQueue); - + return $counter; } @@ -377,4 +377,3 @@ public static function generateJobId() return md5(uniqid('', true)); } } - From da9d780db1a016709728790054574632a333cb2b Mon Sep 17 00:00:00 2001 From: lauripiisang Date: Mon, 29 Aug 2016 18:17:04 +0300 Subject: [PATCH 174/194] Return `false` for 'database' section of unix DSNs This seems to be the expected default value --- lib/Resque/Redis.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 28051275..5d78f6ee 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -166,7 +166,7 @@ public static function parseDsn($dsn) return array( $dsn, null, - null, + false, null, null, null, From 7d2ce1bc8be5042bfcdda611520614f761d7c321 Mon Sep 17 00:00:00 2001 From: Sebastian Machuca Date: Thu, 6 Oct 2016 12:49:15 +1100 Subject: [PATCH 175/194] BIG-28720 Allowing to use a factory instead of manually instantite the Jobs --- lib/Resque/Job.php | 63 +++++++++++++++++++---------- lib/Resque/Job/FactoryInterface.php | 9 +++++ lib/Resque/JobInterface.php | 9 +++++ test/Resque/Tests/JobTest.php | 40 ++++++++++++++++++ test/Resque/Tests/TestCase.php | 7 +++- 5 files changed, 106 insertions(+), 22 deletions(-) create mode 100644 lib/Resque/Job/FactoryInterface.php create mode 100644 lib/Resque/JobInterface.php diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index dfd88692..6c39e181 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -6,7 +6,7 @@ * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ -class Resque_Job +class Resque_Job implements Resque_JobInterface { /** * @var string The name of the queue that this job belongs to. @@ -24,10 +24,15 @@ class Resque_Job public $payload; /** - * @var object Instance of the class performing work for this job. + * @var Resque_JobInterface Instance of the class performing work for this job. */ private $instance; + /** + * @var Resque_Job_FactoryInterface + */ + private $jobFactory; + /** * Instantiate a new instance of a job. * @@ -40,17 +45,18 @@ public function __construct($queue, $payload) $this->payload = $payload; } - /** - * Create a new job and save it to the specified queue. - * - * @param string $queue The name of the queue to place the job in. - * @param string $class The name of the class that contains the code to execute the job. - * @param array $args Any optional arguments that should be passed when the job is executed. - * @param boolean $monitor Set to true to be able to monitor the status of a job. - * @param string $id Unique identifier for tracking the job. Generated if not supplied. - * - * @return string - */ + /** + * Create a new job and save it to the specified queue. + * + * @param string $queue The name of the queue to place the job in. + * @param string $class The name of the class that contains the code to execute the job. + * @param array $args Any optional arguments that should be passed when the job is executed. + * @param boolean $monitor Set to true to be able to monitor the status of a job. + * @param string $id Unique identifier for tracking the job. Generated if not supplied. + * + * @return string + * @throws \InvalidArgumentException + */ public static function create($queue, $class, $args = null, $monitor = false, $id = null) { if (is_null($id)) { @@ -81,7 +87,7 @@ public static function create($queue, $class, $args = null, $monitor = false, $i * instance of Resque_Job for it. * * @param string $queue The name of the queue to check for a job in. - * @return null|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. + * @return false|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. */ public static function reserve($queue) { @@ -99,7 +105,7 @@ public static function reserve($queue) * * @param array $queues * @param int $timeout - * @return null|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. + * @return false|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. */ public static function reserveBlocking(array $queues, $timeout = null) { @@ -152,11 +158,11 @@ 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 Resque_JobInterface Instance of the object that this job belongs to. + * @throws Resque_Exception + */ public function getInstance() { if (!is_null($this->instance)) { @@ -175,7 +181,11 @@ public function getInstance() ); } - $this->instance = new $this->payload['class']; + if ($this->jobFactory !== null) { + $this->instance = $this->jobFactory->create(); + } else { + $this->instance = new $this->payload['class']; + } $this->instance->job = $this; $this->instance->args = $this->getArguments(); $this->instance->queue = $this->queue; @@ -272,4 +282,15 @@ public function __toString() } return '(' . implode(' | ', $name) . ')'; } + + /** + * @param Resque_Job_FactoryInterface $jobFactory + * @return Resque_Job + */ + public function setJobFactory(Resque_Job_FactoryInterface $jobFactory) + { + $this->jobFactory = $jobFactory; + + return $this; + } } diff --git a/lib/Resque/Job/FactoryInterface.php b/lib/Resque/Job/FactoryInterface.php new file mode 100644 index 00000000..9a2b14c3 --- /dev/null +++ b/lib/Resque/Job/FactoryInterface.php @@ -0,0 +1,9 @@ +assertEquals(Resque::size($queue), 2); } + public function testUseFactoryToGetJobInstance() + { + $payload = array( + 'class' => Some_Job_Class::class, + 'args' => null + ); + $job = new Resque_Job('jobs', $payload); + $factory = $this->getMock(Resque_Job_FactoryInterface::class); + $job->setJobFactory($factory); + $testJob = $this->getMock(Resque_JobInterface::class); + $factory->expects(self::once())->method('create')->will($this->returnValue($testJob)); + $instance = $job->getInstance(); + $this->assertInstanceOf(Resque_JobInterface::class, $instance); + } + + public function testDoNotUseFactoryToGetInstance() + { + $payload = array( + 'class' => Some_Job_Class::class, + 'args' => null + ); + $job = new Resque_Job('jobs', $payload); + $factory = $this->getMock(Resque_Job_FactoryInterface::class); + $testJob = $this->getMock(Resque_JobInterface::class); + $factory->expects(self::never())->method('create')->will(self::returnValue($testJob)); + $instance = $job->getInstance(); + $this->assertInstanceOf(Resque_JobInterface::class, $instance); + } +} + +class Some_Job_Class implements Resque_JobInterface +{ + + /** + * @return bool + */ + public function perform() + { + return true; + } } diff --git a/test/Resque/Tests/TestCase.php b/test/Resque/Tests/TestCase.php index 4ed65dee..c828f6f8 100644 --- a/test/Resque/Tests/TestCase.php +++ b/test/Resque/Tests/TestCase.php @@ -11,6 +11,11 @@ class Resque_Tests_TestCase extends PHPUnit_Framework_TestCase protected $resque; protected $redis; + public static function setUpBeforeClass() + { + date_default_timezone_set('UTC'); + } + public function setUp() { $config = file_get_contents(REDIS_CONF); @@ -20,4 +25,4 @@ public function setUp() // Flush redis $this->redis->flushAll(); } -} \ No newline at end of file +} From de22db682686700f96544e089a23cbb1974c1d63 Mon Sep 17 00:00:00 2001 From: Sebastian Machuca Date: Thu, 6 Oct 2016 16:07:16 +1100 Subject: [PATCH 176/194] Making it compatible with PHP < 5.5 Making the factory receive the classname --- lib/Resque/Job.php | 2 +- lib/Resque/Job/FactoryInterface.php | 3 ++- test/Resque/Tests/JobTest.php | 16 ++++++++-------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 6c39e181..31952aa8 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -182,7 +182,7 @@ public function getInstance() } if ($this->jobFactory !== null) { - $this->instance = $this->jobFactory->create(); + $this->instance = $this->jobFactory->create($this->payload['class']); } else { $this->instance = new $this->payload['class']; } diff --git a/lib/Resque/Job/FactoryInterface.php b/lib/Resque/Job/FactoryInterface.php index 9a2b14c3..89edbeec 100644 --- a/lib/Resque/Job/FactoryInterface.php +++ b/lib/Resque/Job/FactoryInterface.php @@ -3,7 +3,8 @@ interface Resque_Job_FactoryInterface { /** + * @param $className * @return Resque_JobInterface */ - public function create(); + public function create($className); } diff --git a/test/Resque/Tests/JobTest.php b/test/Resque/Tests/JobTest.php index 1f2b428d..32111d08 100644 --- a/test/Resque/Tests/JobTest.php +++ b/test/Resque/Tests/JobTest.php @@ -365,30 +365,30 @@ public function testDequeueItemWithiWrongArg() public function testUseFactoryToGetJobInstance() { $payload = array( - 'class' => Some_Job_Class::class, + 'class' => 'Some_Job_Class', 'args' => null ); $job = new Resque_Job('jobs', $payload); - $factory = $this->getMock(Resque_Job_FactoryInterface::class); + $factory = $this->getMock('Resque_Job_FactoryInterface'); $job->setJobFactory($factory); - $testJob = $this->getMock(Resque_JobInterface::class); + $testJob = $this->getMock('Resque_JobInterface'); $factory->expects(self::once())->method('create')->will($this->returnValue($testJob)); $instance = $job->getInstance(); - $this->assertInstanceOf(Resque_JobInterface::class, $instance); + $this->assertInstanceOf('Resque_JobInterface', $instance); } public function testDoNotUseFactoryToGetInstance() { $payload = array( - 'class' => Some_Job_Class::class, + 'class' => 'Some_Job_Class', 'args' => null ); $job = new Resque_Job('jobs', $payload); - $factory = $this->getMock(Resque_Job_FactoryInterface::class); - $testJob = $this->getMock(Resque_JobInterface::class); + $factory = $this->getMock('Resque_Job_FactoryInterface'); + $testJob = $this->getMock('Resque_JobInterface'); $factory->expects(self::never())->method('create')->will(self::returnValue($testJob)); $instance = $job->getInstance(); - $this->assertInstanceOf(Resque_JobInterface::class, $instance); + $this->assertInstanceOf('Resque_JobInterface', $instance); } } From ae308ff1fd738577bd3ad79c981f43ab424281d9 Mon Sep 17 00:00:00 2001 From: Keyan Pishdadian Date: Fri, 7 Oct 2016 18:31:06 -0400 Subject: [PATCH 177/194] Allow empty prefix --- lib/Resque/Redis.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index e588dede..db990cd2 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -98,7 +98,7 @@ class Resque_Redis */ public static function prefix($namespace) { - if (substr($namespace, -1) !== ':') { + if (substr($namespace, -1) !== ':' and $namespace != '') { $namespace .= ':'; } self::$defaultNamespace = $namespace; From eba6ef55e7639165893729215be4f9c2fc6c92fd Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Tue, 11 Oct 2016 12:08:54 -0700 Subject: [PATCH 178/194] abort bin/resque when managing multiple workers and pcntl_fork is unavailable --- bin/resque | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/resque b/bin/resque index 4cb50da5..b445dd2b 100755 --- a/bin/resque +++ b/bin/resque @@ -96,7 +96,7 @@ if(!empty($PREFIX)) { if($count > 1) { for($i = 0; $i < $count; ++$i) { $pid = Resque::fork(); - if($pid == -1) { + if($pid === false || pid === -1) { $logger->log(Psr\Log\LogLevel::EMERGENCY, 'Could not fork worker {count}', array('count' => $i)); die(); } From 59ae24d0b51be9a9ca53f42f1d4dd12b8e146fa6 Mon Sep 17 00:00:00 2001 From: Serghei Iakovlev Date: Wed, 12 Oct 2016 00:51:55 +0300 Subject: [PATCH 179/194] Update Readme.md [ci skip] --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c4da4ba4..cd8f83fe 100644 --- a/README.md +++ b/README.md @@ -53,11 +53,9 @@ If you're not familiar with Composer, please see . ```json { - // ... "require": { - "chrisboulton/php-resque": "1.2.x" // Most recent tagged version - }, - // ... + "chrisboulton/php-resque": "1.2.x" + } } ``` From 8f542e5035c12f27e74b3c223ecf9c566381bd64 Mon Sep 17 00:00:00 2001 From: Sebastian Machuca Date: Wed, 12 Oct 2016 19:22:31 +1100 Subject: [PATCH 180/194] Making the factory responsible to set the arguments and the queue --- lib/Resque/Job.php | 13 +++++++------ lib/Resque/Job/FactoryInterface.php | 4 +++- test/Resque/Tests/JobTest.php | 19 ++++++++++++++++--- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 31952aa8..1465b361 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -182,13 +182,14 @@ public function getInstance() } if ($this->jobFactory !== null) { - $this->instance = $this->jobFactory->create($this->payload['class']); - } else { - $this->instance = new $this->payload['class']; + $this->instance = $this->jobFactory->create($this->payload['class'], $this->getArguments(), $this->queue); + return $this->instance; } - $this->instance->job = $this; - $this->instance->args = $this->getArguments(); - $this->instance->queue = $this->queue; + $this->instance = new $this->payload['class']; + $this->instance->job = $this; + $this->instance->args = $this->getArguments(); + $this->instance->queue = $this->queue; + return $this->instance; } diff --git a/lib/Resque/Job/FactoryInterface.php b/lib/Resque/Job/FactoryInterface.php index 89edbeec..d12211d3 100644 --- a/lib/Resque/Job/FactoryInterface.php +++ b/lib/Resque/Job/FactoryInterface.php @@ -4,7 +4,9 @@ interface Resque_Job_FactoryInterface { /** * @param $className + * @param array $args + * @param $queue * @return Resque_JobInterface */ - public function create($className); + public function create($className, array $args, $queue); } diff --git a/test/Resque/Tests/JobTest.php b/test/Resque/Tests/JobTest.php index 32111d08..a71e6f06 100644 --- a/test/Resque/Tests/JobTest.php +++ b/test/Resque/Tests/JobTest.php @@ -369,10 +369,8 @@ public function testUseFactoryToGetJobInstance() 'args' => null ); $job = new Resque_Job('jobs', $payload); - $factory = $this->getMock('Resque_Job_FactoryInterface'); + $factory = new Some_Stub_Factory(); $job->setJobFactory($factory); - $testJob = $this->getMock('Resque_JobInterface'); - $factory->expects(self::once())->method('create')->will($this->returnValue($testJob)); $instance = $job->getInstance(); $this->assertInstanceOf('Resque_JobInterface', $instance); } @@ -403,3 +401,18 @@ public function perform() return true; } } + +class Some_Stub_Factory implements Resque_Job_FactoryInterface +{ + + /** + * @param $className + * @param array $args + * @param $queue + * @return Resque_JobInterface + */ + public function create($className, array $args, $queue) + { + return new Some_Job_Class(); + } +} From df20186c37011786f150c7e2867961dadc5f385e Mon Sep 17 00:00:00 2001 From: Sebastian Machuca Date: Thu, 13 Oct 2016 14:45:02 +1100 Subject: [PATCH 181/194] Convert spaces to tabs --- lib/Resque/Job.php | 146 ++++++++++++++-------------- lib/Resque/Job/FactoryInterface.php | 14 +-- lib/Resque/JobInterface.php | 8 +- test/Resque/Tests/JobTest.php | 104 ++++++++++---------- test/Resque/Tests/TestCase.php | 8 +- 5 files changed, 140 insertions(+), 140 deletions(-) diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index 1465b361..bb79f32c 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -28,10 +28,10 @@ class Resque_Job implements Resque_JobInterface */ private $instance; - /** - * @var Resque_Job_FactoryInterface - */ - private $jobFactory; + /** + * @var Resque_Job_FactoryInterface + */ + private $jobFactory; /** * Instantiate a new instance of a job. @@ -45,18 +45,18 @@ public function __construct($queue, $payload) $this->payload = $payload; } - /** - * Create a new job and save it to the specified queue. - * - * @param string $queue The name of the queue to place the job in. - * @param string $class The name of the class that contains the code to execute the job. - * @param array $args Any optional arguments that should be passed when the job is executed. - * @param boolean $monitor Set to true to be able to monitor the status of a job. - * @param string $id Unique identifier for tracking the job. Generated if not supplied. - * - * @return string - * @throws \InvalidArgumentException - */ + /** + * Create a new job and save it to the specified queue. + * + * @param string $queue The name of the queue to place the job in. + * @param string $class The name of the class that contains the code to execute the job. + * @param array $args Any optional arguments that should be passed when the job is executed. + * @param boolean $monitor Set to true to be able to monitor the status of a job. + * @param string $id Unique identifier for tracking the job. Generated if not supplied. + * + * @return string + * @throws \InvalidArgumentException + */ public static function create($queue, $class, $args = null, $monitor = false, $id = null) { if (is_null($id)) { @@ -82,41 +82,41 @@ public static function create($queue, $class, $args = null, $monitor = false, $i return $id; } - /** - * Find the next available job from the specified queue and return an - * instance of Resque_Job for it. - * - * @param string $queue The name of the queue to check for a job in. - * @return false|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. - */ - public static function reserve($queue) - { - $payload = Resque::pop($queue); - if(!is_array($payload)) { - return false; - } - - return new Resque_Job($queue, $payload); - } - - /** - * Find the next available job from the specified queues using blocking list pop - * and return an instance of Resque_Job for it. - * - * @param array $queues - * @param int $timeout - * @return false|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. - */ - public static function reserveBlocking(array $queues, $timeout = null) - { - $item = Resque::blpop($queues, $timeout); - - if(!is_array($item)) { - return false; - } - - return new Resque_Job($item['queue'], $item['payload']); - } + /** + * Find the next available job from the specified queue and return an + * instance of Resque_Job for it. + * + * @param string $queue The name of the queue to check for a job in. + * @return false|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. + */ + public static function reserve($queue) + { + $payload = Resque::pop($queue); + if(!is_array($payload)) { + return false; + } + + return new Resque_Job($queue, $payload); + } + + /** + * Find the next available job from the specified queues using blocking list pop + * and return an instance of Resque_Job for it. + * + * @param array $queues + * @param int $timeout + * @return false|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. + */ + public static function reserveBlocking(array $queues, $timeout = null) + { + $item = Resque::blpop($queues, $timeout); + + if(!is_array($item)) { + return false; + } + + return new Resque_Job($item['queue'], $item['payload']); + } /** * Update the status of the current job. @@ -158,11 +158,11 @@ public function getArguments() return $this->payload['args'][0]; } - /** - * Get the instantiated object for this job that will be performing work. - * @return Resque_JobInterface Instance of the object that this job belongs to. - * @throws Resque_Exception - */ + /** + * Get the instantiated object for this job that will be performing work. + * @return Resque_JobInterface Instance of the object that this job belongs to. + * @throws Resque_Exception + */ public function getInstance() { if (!is_null($this->instance)) { @@ -181,14 +181,14 @@ public function getInstance() ); } - if ($this->jobFactory !== null) { - $this->instance = $this->jobFactory->create($this->payload['class'], $this->getArguments(), $this->queue); - return $this->instance; - } - $this->instance = new $this->payload['class']; - $this->instance->job = $this; - $this->instance->args = $this->getArguments(); - $this->instance->queue = $this->queue; + if ($this->jobFactory !== null) { + $this->instance = $this->jobFactory->create($this->payload['class'], $this->getArguments(), $this->queue); + return $this->instance; + } + $this->instance = new $this->payload['class']; + $this->instance->job = $this; + $this->instance->args = $this->getArguments(); + $this->instance->queue = $this->queue; return $this->instance; } @@ -284,14 +284,14 @@ public function __toString() return '(' . implode(' | ', $name) . ')'; } - /** - * @param Resque_Job_FactoryInterface $jobFactory - * @return Resque_Job - */ - public function setJobFactory(Resque_Job_FactoryInterface $jobFactory) - { - $this->jobFactory = $jobFactory; + /** + * @param Resque_Job_FactoryInterface $jobFactory + * @return Resque_Job + */ + public function setJobFactory(Resque_Job_FactoryInterface $jobFactory) + { + $this->jobFactory = $jobFactory; - return $this; - } + return $this; + } } diff --git a/lib/Resque/Job/FactoryInterface.php b/lib/Resque/Job/FactoryInterface.php index d12211d3..be573a2a 100644 --- a/lib/Resque/Job/FactoryInterface.php +++ b/lib/Resque/Job/FactoryInterface.php @@ -2,11 +2,11 @@ interface Resque_Job_FactoryInterface { - /** - * @param $className - * @param array $args - * @param $queue - * @return Resque_JobInterface - */ - public function create($className, array $args, $queue); + /** + * @param $className + * @param array $args + * @param $queue + * @return Resque_JobInterface + */ + public function create($className, array $args, $queue); } diff --git a/lib/Resque/JobInterface.php b/lib/Resque/JobInterface.php index f31281dd..be5891db 100644 --- a/lib/Resque/JobInterface.php +++ b/lib/Resque/JobInterface.php @@ -2,8 +2,8 @@ interface Resque_JobInterface { - /** - * @return bool - */ - public function perform(); + /** + * @return bool + */ + public function perform(); } diff --git a/test/Resque/Tests/JobTest.php b/test/Resque/Tests/JobTest.php index a71e6f06..a1788ed4 100644 --- a/test/Resque/Tests/JobTest.php +++ b/test/Resque/Tests/JobTest.php @@ -183,16 +183,16 @@ public function testNamespaceNaming() { public function testJobWithNamespace() { - Resque_Redis::prefix('php'); - $queue = 'jobs'; - $payload = array('another_value'); - Resque::enqueue($queue, 'Test_Job_With_TearDown', $payload); - - $this->assertEquals(Resque::queues(), array('jobs')); - $this->assertEquals(Resque::size($queue), 1); - - Resque_Redis::prefix('resque'); - $this->assertEquals(Resque::size($queue), 0); + Resque_Redis::prefix('php'); + $queue = 'jobs'; + $payload = array('another_value'); + Resque::enqueue($queue, 'Test_Job_With_TearDown', $payload); + + $this->assertEquals(Resque::queues(), array('jobs')); + $this->assertEquals(Resque::size($queue), 1); + + Resque_Redis::prefix('resque'); + $this->assertEquals(Resque::size($queue), 0); } public function testDequeueAll() @@ -363,56 +363,56 @@ public function testDequeueItemWithiWrongArg() } public function testUseFactoryToGetJobInstance() - { - $payload = array( - 'class' => 'Some_Job_Class', - 'args' => null - ); - $job = new Resque_Job('jobs', $payload); - $factory = new Some_Stub_Factory(); - $job->setJobFactory($factory); - $instance = $job->getInstance(); - $this->assertInstanceOf('Resque_JobInterface', $instance); - } - - public function testDoNotUseFactoryToGetInstance() - { - $payload = array( - 'class' => 'Some_Job_Class', - 'args' => null - ); - $job = new Resque_Job('jobs', $payload); - $factory = $this->getMock('Resque_Job_FactoryInterface'); - $testJob = $this->getMock('Resque_JobInterface'); - $factory->expects(self::never())->method('create')->will(self::returnValue($testJob)); - $instance = $job->getInstance(); - $this->assertInstanceOf('Resque_JobInterface', $instance); - } + { + $payload = array( + 'class' => 'Some_Job_Class', + 'args' => null + ); + $job = new Resque_Job('jobs', $payload); + $factory = new Some_Stub_Factory(); + $job->setJobFactory($factory); + $instance = $job->getInstance(); + $this->assertInstanceOf('Resque_JobInterface', $instance); + } + + public function testDoNotUseFactoryToGetInstance() + { + $payload = array( + 'class' => 'Some_Job_Class', + 'args' => null + ); + $job = new Resque_Job('jobs', $payload); + $factory = $this->getMock('Resque_Job_FactoryInterface'); + $testJob = $this->getMock('Resque_JobInterface'); + $factory->expects(self::never())->method('create')->will(self::returnValue($testJob)); + $instance = $job->getInstance(); + $this->assertInstanceOf('Resque_JobInterface', $instance); + } } class Some_Job_Class implements Resque_JobInterface { - /** - * @return bool - */ - public function perform() - { - return true; - } + /** + * @return bool + */ + public function perform() + { + return true; + } } class Some_Stub_Factory implements Resque_Job_FactoryInterface { - /** - * @param $className - * @param array $args - * @param $queue - * @return Resque_JobInterface - */ - public function create($className, array $args, $queue) - { - return new Some_Job_Class(); - } + /** + * @param $className + * @param array $args + * @param $queue + * @return Resque_JobInterface + */ + public function create($className, array $args, $queue) + { + return new Some_Job_Class(); + } } diff --git a/test/Resque/Tests/TestCase.php b/test/Resque/Tests/TestCase.php index c828f6f8..6a01219a 100644 --- a/test/Resque/Tests/TestCase.php +++ b/test/Resque/Tests/TestCase.php @@ -11,10 +11,10 @@ class Resque_Tests_TestCase extends PHPUnit_Framework_TestCase protected $resque; protected $redis; - public static function setUpBeforeClass() - { - date_default_timezone_set('UTC'); - } + public static function setUpBeforeClass() + { + date_default_timezone_set('UTC'); + } public function setUp() { From be19e12c315923345d9d6c5b911d57cdfaad012b Mon Sep 17 00:00:00 2001 From: Sebastian Machuca Date: Fri, 14 Oct 2016 14:41:19 +1100 Subject: [PATCH 182/194] Making the factory the default layer to construct jobs --- lib/Resque/Job.php | 40 ++++++++++++----------------- lib/Resque/Job/Factory.php | 32 +++++++++++++++++++++++ lib/Resque/Job/FactoryInterface.php | 2 +- test/Resque/Tests/EventTest.php | 2 +- test/Resque/Tests/JobTest.php | 17 +++++++++--- 5 files changed, 64 insertions(+), 29 deletions(-) create mode 100644 lib/Resque/Job/Factory.php diff --git a/lib/Resque/Job.php b/lib/Resque/Job.php index bb79f32c..8508f766 100755 --- a/lib/Resque/Job.php +++ b/lib/Resque/Job.php @@ -6,7 +6,7 @@ * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ -class Resque_Job implements Resque_JobInterface +class Resque_Job { /** * @var string The name of the queue that this job belongs to. @@ -24,7 +24,7 @@ class Resque_Job implements Resque_JobInterface public $payload; /** - * @var Resque_JobInterface Instance of the class performing work for this job. + * @var object|Resque_JobInterface Instance of the class performing work for this job. */ private $instance; @@ -169,28 +169,9 @@ public function getInstance() return $this->instance; } - if(!class_exists($this->payload['class'])) { - throw new Resque_Exception( - 'Could not find job class ' . $this->payload['class'] . '.' - ); - } - - if(!method_exists($this->payload['class'], 'perform')) { - throw new Resque_Exception( - 'Job class ' . $this->payload['class'] . ' does not contain a perform method.' - ); - } - - if ($this->jobFactory !== null) { - $this->instance = $this->jobFactory->create($this->payload['class'], $this->getArguments(), $this->queue); - return $this->instance; - } - $this->instance = new $this->payload['class']; - $this->instance->job = $this; - $this->instance->args = $this->getArguments(); - $this->instance->queue = $this->queue; - - return $this->instance; + $this->instance = $this->getJobFactory()->create($this->payload['class'], $this->getArguments(), $this->queue); + $this->instance->job = $this; + return $this->instance; } /** @@ -294,4 +275,15 @@ public function setJobFactory(Resque_Job_FactoryInterface $jobFactory) return $this; } + + /** + * @return Resque_Job_FactoryInterface + */ + public function getJobFactory() + { + if ($this->jobFactory === null) { + $this->jobFactory = new Resque_Job_Factory(); + } + return $this->jobFactory; + } } diff --git a/lib/Resque/Job/Factory.php b/lib/Resque/Job/Factory.php new file mode 100644 index 00000000..cf172944 --- /dev/null +++ b/lib/Resque/Job/Factory.php @@ -0,0 +1,32 @@ +args = $args; + $instance->queue = $queue; + return $instance; + } +} diff --git a/lib/Resque/Job/FactoryInterface.php b/lib/Resque/Job/FactoryInterface.php index be573a2a..b8c102cf 100644 --- a/lib/Resque/Job/FactoryInterface.php +++ b/lib/Resque/Job/FactoryInterface.php @@ -8,5 +8,5 @@ interface Resque_Job_FactoryInterface * @param $queue * @return Resque_JobInterface */ - public function create($className, array $args, $queue); + public function create($className, $args, $queue); } diff --git a/test/Resque/Tests/EventTest.php b/test/Resque/Tests/EventTest.php index 1147c991..6e102cf4 100644 --- a/test/Resque/Tests/EventTest.php +++ b/test/Resque/Tests/EventTest.php @@ -31,7 +31,7 @@ public function getEventTestJob() $payload = array( 'class' => 'Test_Job', 'args' => array( - 'somevar', + array('somevar'), ), ); $job = new Resque_Job('jobs', $payload); diff --git a/test/Resque/Tests/JobTest.php b/test/Resque/Tests/JobTest.php index a1788ed4..fe58ce4d 100644 --- a/test/Resque/Tests/JobTest.php +++ b/test/Resque/Tests/JobTest.php @@ -362,13 +362,24 @@ public function testDequeueItemWithiWrongArg() $this->assertEquals(Resque::size($queue), 2); } - public function testUseFactoryToGetJobInstance() + public function testUseDefaultFactoryToGetJobInstance() { $payload = array( 'class' => 'Some_Job_Class', 'args' => null ); $job = new Resque_Job('jobs', $payload); + $instance = $job->getInstance(); + $this->assertInstanceOf('Some_Job_Class', $instance); + } + + public function testUseFactoryToGetJobInstance() + { + $payload = array( + 'class' => 'Some_Job_Class', + 'args' => array(array()) + ); + $job = new Resque_Job('jobs', $payload); $factory = new Some_Stub_Factory(); $job->setJobFactory($factory); $instance = $job->getInstance(); @@ -379,7 +390,7 @@ public function testDoNotUseFactoryToGetInstance() { $payload = array( 'class' => 'Some_Job_Class', - 'args' => null + 'args' => array(array()) ); $job = new Resque_Job('jobs', $payload); $factory = $this->getMock('Resque_Job_FactoryInterface'); @@ -411,7 +422,7 @@ class Some_Stub_Factory implements Resque_Job_FactoryInterface * @param $queue * @return Resque_JobInterface */ - public function create($className, array $args, $queue) + public function create($className, $args, $queue) { return new Some_Job_Class(); } From 81cb92b9640aeb278b71e98b2ce0fe77cf2e522e Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Mon, 2 Feb 2015 14:00:16 -0800 Subject: [PATCH 183/194] throw Resque_RedisException whenever an errror connecting/talking to redis occurs --- lib/Resque/Redis.php | 48 ++++++++++--------- test/Resque/Tests/JobTest.php | 9 ++++ .../Tests/{DsnTest.php => RedisTest.php} | 17 +++++-- test/Resque/Tests/TestCase.php | 2 + 4 files changed, 49 insertions(+), 27 deletions(-) rename test/Resque/Tests/{DsnTest.php => RedisTest.php} (91%) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 1ba4cccf..2c0a11e1 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -111,34 +111,38 @@ public static function prefix($namespace) */ public function __construct($server, $database = null) { - if (is_array($server)) { - $this->driver = new Credis_Cluster($server); - } - else { + try { + if (is_array($server)) { + $this->driver = new Credis_Cluster($server); + } + else { + list($host, $port, $dsnDatabase, $user, $password, $options) = self::parseDsn($server); + // $user is not used, only $password - list($host, $port, $dsnDatabase, $user, $password, $options) = self::parseDsn($server); - // $user is not used, only $password + // Look for known Credis_Client options + $timeout = isset($options['timeout']) ? intval($options['timeout']) : null; + $persistent = isset($options['persistent']) ? $options['persistent'] : ''; + $maxRetries = isset($options['max_connect_retries']) ? $options['max_connect_retries'] : 0; - // Look for known Credis_Client options - $timeout = isset($options['timeout']) ? intval($options['timeout']) : null; - $persistent = isset($options['persistent']) ? $options['persistent'] : ''; - $maxRetries = isset($options['max_connect_retries']) ? $options['max_connect_retries'] : 0; + $this->driver = new Credis_Client($host, $port, $timeout, $persistent); + $this->driver->setMaxConnectRetries($maxRetries); + if ($password){ + $this->driver->auth($password); + } - $this->driver = new Credis_Client($host, $port, $timeout, $persistent); - $this->driver->setMaxConnectRetries($maxRetries); - if ($password){ - $this->driver->auth($password); + // If we have found a database in our DSN, use it instead of the `$database` + // value passed into the constructor. + if ($dsnDatabase !== false) { + $database = $dsnDatabase; + } } - // If we have found a database in our DSN, use it instead of the `$database` - // value passed into the constructor. - if ($dsnDatabase !== false) { - $database = $dsnDatabase; + if ($database !== null) { + $this->driver->select($database); } } - - if ($database !== null) { - $this->driver->select($database); + catch(CredisException $e) { + throw new Resque_RedisException($e); } } @@ -241,7 +245,7 @@ public function __call($name, $args) return $this->driver->__call($name, $args); } catch (CredisException $e) { - return false; + throw new Resque_RedisException($e); } } diff --git a/test/Resque/Tests/JobTest.php b/test/Resque/Tests/JobTest.php index fe58ce4d..ab55673b 100644 --- a/test/Resque/Tests/JobTest.php +++ b/test/Resque/Tests/JobTest.php @@ -26,6 +26,15 @@ public function testJobCanBeQueued() $this->assertTrue((bool)Resque::enqueue('jobs', 'Test_Job')); } + /** + * @expectedException Resque_RedisException + */ + public function testRedisErrorThrowsExceptionOnJobCreation() + { + Resque::setBackend('redis://255.255.255.255:1234'); + Resque::enqueue('jobs', 'This is a test'); + } + public function testQeueuedJobCanBeReserved() { Resque::enqueue('jobs', 'Test_Job'); diff --git a/test/Resque/Tests/DsnTest.php b/test/Resque/Tests/RedisTest.php similarity index 91% rename from test/Resque/Tests/DsnTest.php rename to test/Resque/Tests/RedisTest.php index 086db1ea..a2895dec 100644 --- a/test/Resque/Tests/DsnTest.php +++ b/test/Resque/Tests/RedisTest.php @@ -1,13 +1,21 @@ + * @author Chris Boulton * @license http://www.opensource.org/licenses/mit-license.php */ -class Resque_Tests_DsnTest extends Resque_Tests_TestCase +class Resque_Tests_RedisTest extends Resque_Tests_TestCase { + /** + * @expectedException Resque_RedisException + */ + public function testRedisExceptionsAreSurfaced() + { + $redis = new Resque_Redis('redis://255.255.255.255:1234'); + $redis->ping(); + } /** * These DNS strings are considered valid. @@ -178,5 +186,4 @@ public function testParsingBogusDsnStringThrowsException($dsn) // The next line should throw an InvalidArgumentException $result = Resque_Redis::parseDsn($dsn); } - -} +} \ No newline at end of file diff --git a/test/Resque/Tests/TestCase.php b/test/Resque/Tests/TestCase.php index 6a01219a..a97f64bf 100644 --- a/test/Resque/Tests/TestCase.php +++ b/test/Resque/Tests/TestCase.php @@ -22,6 +22,8 @@ public function setUp() preg_match('#^\s*port\s+([0-9]+)#m', $config, $matches); $this->redis = new Credis_Client('localhost', $matches[1]); + Resque::setBackend('redis://localhost:' . $matches[1]); + // Flush redis $this->redis->flushAll(); } From af570212b35b55bc4f8e546208ae1ff358ef613b Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Mon, 2 Feb 2015 14:13:36 -0800 Subject: [PATCH 184/194] add Resque_RedisException --- lib/Resque/RedisException.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 lib/Resque/RedisException.php diff --git a/lib/Resque/RedisException.php b/lib/Resque/RedisException.php new file mode 100644 index 00000000..ca654a00 --- /dev/null +++ b/lib/Resque/RedisException.php @@ -0,0 +1,12 @@ + + * @license http://www.opensource.org/licenses/mit-license.php + */ +class Resque_RedisException extends Resque_Exception +{ +} +?> \ No newline at end of file From b1911f6867209f148511965518bbea333073e078 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Tue, 3 Feb 2015 09:54:03 -0800 Subject: [PATCH 185/194] maintain previous credis exception when throwing redis exceptions from resque --- lib/Resque/Redis.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 2c0a11e1..11762325 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -142,7 +142,7 @@ public function __construct($server, $database = null) } } catch(CredisException $e) { - throw new Resque_RedisException($e); + throw new Resque_RedisException('Error communicating with Redis: ' . $e->getMessage(), 0, $e); } } @@ -245,7 +245,7 @@ public function __call($name, $args) return $this->driver->__call($name, $args); } catch (CredisException $e) { - throw new Resque_RedisException($e); + throw new Resque_RedisException('Error communicating with Redis: ' . $e->getMessage(), 0, $e); } } From 2e24b5308f19a94ef038e9c5e134a294618f55fe Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Fri, 14 Oct 2016 15:26:02 -0700 Subject: [PATCH 186/194] don't test against php 5.3, 5.4, 5.5. don't allow failures on php7 and hhvm --- .travis.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 46d39196..8a3ac023 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,20 +1,11 @@ language: php php: - - 5.3 - - 5.4 - - 5.5 - 5.6 - 7.0 - hhvm - -matrix: - allow_failures: - - php: hhvm - - php: 7.0 env: - REDIS_STANDALONE=0 - REDIS_STANDALONE=1 - before_script: - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then wget https://github.com/nicolasff/phpredis/archive/2.2.3.zip -O php-redis.zip && unzip php-redis.zip; fi" - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then cd phpredis-2.2.3/ && phpize && ./configure && make && make install; fi" From 89895644688524033366cb52ce827c431049ce00 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Fri, 14 Oct 2016 15:49:33 -0700 Subject: [PATCH 187/194] enable redis extension on supported php versions --- .travis.yml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8a3ac023..2fa42c83 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,16 @@ language: php -php: - - 5.6 - - 7.0 - - hhvm -env: - - REDIS_STANDALONE=0 - - REDIS_STANDALONE=1 +matrix: + include: + - php: 5.6 + env: ENABLE_REDIS_EXT=0 + - php: 5.6 + env: ENABLE_REDIS_EXT=1 + - php: 7.0 + env: ENABLE_REDIS_EXT=0 + - php: 7.0 + env: ENABLE_REDIS_EXT=1 + - php: hhvm + env: ENABLE_REDIS_EXT=0 before_script: - - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then wget https://github.com/nicolasff/phpredis/archive/2.2.3.zip -O php-redis.zip && unzip php-redis.zip; fi" - - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then cd phpredis-2.2.3/ && phpize && ./configure && make && make install; fi" - - sh -c "if [ $REDIS_STANDALONE -eq 0 ]; then echo \"extension=redis.so\" >> `php --ini | grep \"Loaded Configuration\" | sed -e \"s|.*:\s*||\"`; fi" + - sh -c "if [ $ENABLE_REDIS_EXT -eq 1 ]; then echo \"extension=redis.so\" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi" - composer install From 4b10ae48638709fc534c61294ad904f179d3a85a Mon Sep 17 00:00:00 2001 From: Dan Hunsaker Date: Fri, 14 Oct 2016 21:01:51 -0600 Subject: [PATCH 188/194] Use Matrix Exclude instead of hard-coded matrix While the current .travis.yml setup works, and the reasoning makes sense, it's far less readable than the previous configuration. This suggested patch presents an alternative approach to the same result, which uses the matrix->exclude array to filter out invalid tests, instead of hard-coding every valid combination as the current file does. This seems more readable, at least to me. --- .travis.yml | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2fa42c83..8a18b81e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,15 @@ language: php +php: + - 5.6 + - 7.0 + - hhvm matrix: - include: - - php: 5.6 - env: ENABLE_REDIS_EXT=0 - - php: 5.6 - env: ENABLE_REDIS_EXT=1 - - php: 7.0 - env: ENABLE_REDIS_EXT=0 - - php: 7.0 - env: ENABLE_REDIS_EXT=1 + exclude: - php: hhvm - env: ENABLE_REDIS_EXT=0 + env: ENABLE_REDIS_EXT=1 +env: + - ENABLE_REDIS_EXT=0 + - ENABLE_REDIS_EXT=1 before_script: - sh -c "if [ $ENABLE_REDIS_EXT -eq 1 ]; then echo \"extension=redis.so\" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi" - composer install From 8113e624c4e5458db44a0fc1845576312bd57803 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Sat, 15 Oct 2016 01:44:03 -0700 Subject: [PATCH 189/194] use a mock to test correct redis exceptions are surfaced --- lib/Resque/Redis.php | 6 +++++- test/Resque/Tests/JobTest.php | 10 +++++++++- test/Resque/Tests/RedisTest.php | 12 ++++++++++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 11762325..3b6b643f 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -108,13 +108,17 @@ public static function prefix($namespace) * @param string|array $server A DSN or array * @param int $database A database number to select. However, if we find a valid database number in the DSN the * DSN-supplied value will be used instead and this parameter is ignored. + * @param object $client Optional Credis_Cluster or Credis_Client instance instantiated by you */ - public function __construct($server, $database = null) + public function __construct($server, $database = null, $client = null) { try { if (is_array($server)) { $this->driver = new Credis_Cluster($server); } + else if (is_object($client)) { + $this->driver = $client; + } else { list($host, $port, $dsnDatabase, $user, $password, $options) = self::parseDsn($server); // $user is not used, only $password diff --git a/test/Resque/Tests/JobTest.php b/test/Resque/Tests/JobTest.php index ab55673b..fb55d13b 100644 --- a/test/Resque/Tests/JobTest.php +++ b/test/Resque/Tests/JobTest.php @@ -31,7 +31,15 @@ public function testJobCanBeQueued() */ public function testRedisErrorThrowsExceptionOnJobCreation() { - Resque::setBackend('redis://255.255.255.255:1234'); + $mockCredis = $this->getMockBuilder('Credis_Client') + ->setMethods(['connect', '__call']) + ->getMock(); + $mockCredis->expects($this->any())->method('__call') + ->will($this->throwException(new CredisException('failure'))); + + Resque::setBackend(function($database) use ($mockCredis) { + return new Resque_Redis('localhost:6379', $database, $mockCredis); + }); Resque::enqueue('jobs', 'This is a test'); } diff --git a/test/Resque/Tests/RedisTest.php b/test/Resque/Tests/RedisTest.php index a2895dec..55b5e17d 100644 --- a/test/Resque/Tests/RedisTest.php +++ b/test/Resque/Tests/RedisTest.php @@ -13,8 +13,16 @@ class Resque_Tests_RedisTest extends Resque_Tests_TestCase */ public function testRedisExceptionsAreSurfaced() { - $redis = new Resque_Redis('redis://255.255.255.255:1234'); - $redis->ping(); + $mockCredis = $this->getMockBuilder('Credis_Client') + ->setMethods(['connect', '__call']) + ->getMock(); + $mockCredis->expects($this->any())->method('__call') + ->will($this->throwException(new CredisException('failure'))); + + Resque::setBackend(function($database) use ($mockCredis) { + return new Resque_Redis('localhost:6379', $database, $mockCredis); + }); + Resque::redis()->ping(); } /** From 3b676e8d6a2c60d475e49a45a4c4045b0ea3fe73 Mon Sep 17 00:00:00 2001 From: Chris Boulton Date: Fri, 14 Oct 2016 16:47:31 -0700 Subject: [PATCH 190/194] bump credis to 1.7 --- composer.json | 2 +- composer.lock | 143 ++++++++++++++++++++++++-------------------------- 2 files changed, 71 insertions(+), 74 deletions(-) diff --git a/composer.json b/composer.json index 6e31daac..28a0bf58 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "require": { "php": ">=5.3.0", "ext-pcntl": "*", - "colinmollenhour/credis": "~1.2", + "colinmollenhour/credis": "~1.7", "psr/log": "1.0.0" }, "suggest": { diff --git a/composer.lock b/composer.lock index 1ecf21a5..0f431b90 100644 --- a/composer.lock +++ b/composer.lock @@ -1,33 +1,35 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "1862fac0c6f40ddf7d98bcef5f4bbd77", + "hash": "41124ffd15a15b52947e430b92b8f10f", + "content-hash": "11906622d4e017ff6807c6dff51f208d", "packages": [ { "name": "colinmollenhour/credis", - "version": "1.4", + "version": "1.7", "source": { "type": "git", "url": "https://github.com/colinmollenhour/credis.git", - "reference": "2079564c61cc49867eddc3cc918c711564164d65" + "reference": "74b2b703da5c58dc07fb97e8954bc63280b469bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/colinmollenhour/credis/zipball/2079564c61cc49867eddc3cc918c711564164d65", - "reference": "2079564c61cc49867eddc3cc918c711564164d65", + "url": "https://api.github.com/repos/colinmollenhour/credis/zipball/74b2b703da5c58dc07fb97e8954bc63280b469bf", + "reference": "74b2b703da5c58dc07fb97e8954bc63280b469bf", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=5.4.0" }, "type": "library", "autoload": { "classmap": [ "Client.php", - "Cluster.php" + "Cluster.php", + "Sentinel.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -42,7 +44,7 @@ ], "description": "Credis is a lightweight interface to the Redis key-value store which wraps the phpredis library when available for better performance.", "homepage": "https://github.com/colinmollenhour/credis", - "time": "2014-05-05 19:31:30" + "time": "2016-03-24 15:50:52" }, { "name": "psr/log", @@ -86,23 +88,23 @@ "packages-dev": [ { "name": "phpunit/php-code-coverage", - "version": "1.2.17", + "version": "1.2.18", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "6ef2bf3a1c47eca07ea95f0d8a902a6340390b34" + "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6ef2bf3a1c47eca07ea95f0d8a902a6340390b34", - "reference": "6ef2bf3a1c47eca07ea95f0d8a902a6340390b34", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", + "reference": "fe2466802556d3fe4e4d1d58ffd3ccfd0a19be0b", "shasum": "" }, "require": { "php": ">=5.3.3", "phpunit/php-file-iterator": ">=1.3.0@stable", "phpunit/php-text-template": ">=1.2.0@stable", - "phpunit/php-token-stream": ">=1.1.3@stable" + "phpunit/php-token-stream": ">=1.1.3,<1.3.0" }, "require-dev": { "phpunit/phpunit": "3.7.*@dev" @@ -143,35 +145,37 @@ "testing", "xunit" ], - "time": "2014-03-28 10:53:45" + "time": "2014-09-02 10:13:14" }, { "name": "phpunit/php-file-iterator", - "version": "1.3.4", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", - "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", "shasum": "" }, "require": { "php": ">=5.3.3" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, "autoload": { "classmap": [ - "File/" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], "license": [ "BSD-3-Clause" ], @@ -188,20 +192,20 @@ "filesystem", "iterator" ], - "time": "2013-10-10 15:34:57" + "time": "2015-06-21 13:08:43" }, { "name": "phpunit/php-text-template", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", - "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", "shasum": "" }, "require": { @@ -210,20 +214,17 @@ "type": "library", "autoload": { "classmap": [ - "Text/" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], "license": [ "BSD-3-Clause" ], "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -232,35 +233,35 @@ "keywords": [ "template" ], - "time": "2014-01-30 17:20:04" + "time": "2015-06-21 13:50:34" }, { "name": "phpunit/php-timer", - "version": "1.0.5", + "version": "1.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", - "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", "shasum": "" }, "require": { "php": ">=5.3.3" }, + "require-dev": { + "phpunit/phpunit": "~4|~5" + }, "type": "library", "autoload": { "classmap": [ - "PHP/" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], "license": [ "BSD-3-Clause" ], @@ -276,7 +277,7 @@ "keywords": [ "timer" ], - "time": "2013-08-02 07:42:54" + "time": "2016-05-12 18:03:57" }, { "name": "phpunit/php-token-stream", @@ -330,16 +331,16 @@ }, { "name": "phpunit/phpunit", - "version": "3.7.37", + "version": "3.7.38", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "ae6cefd7cc84586a5ef27e04bae11ee940ec63dc" + "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ae6cefd7cc84586a5ef27e04bae11ee940ec63dc", - "reference": "ae6cefd7cc84586a5ef27e04bae11ee940ec63dc", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/38709dc22d519a3d1be46849868aa2ddf822bcf6", + "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6", "shasum": "" }, "require": { @@ -399,7 +400,7 @@ "testing", "xunit" ], - "time": "2014-04-30 12:24:19" + "time": "2014-10-17 09:04:17" }, { "name": "phpunit/phpunit-mock-objects", @@ -452,32 +453,34 @@ }, { "name": "symfony/yaml", - "version": "v2.5.0", - "target-dir": "Symfony/Component/Yaml", + "version": "v2.8.12", "source": { "type": "git", - "url": "https://github.com/symfony/Yaml.git", - "reference": "b4b09c68ec2f2727574544ef0173684281a5033c" + "url": "https://github.com/symfony/yaml.git", + "reference": "e7540734bad981fe59f8ef14b6fc194ae9df8d9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/b4b09c68ec2f2727574544ef0173684281a5033c", - "reference": "b4b09c68ec2f2727574544ef0173684281a5033c", + "url": "https://api.github.com/repos/symfony/yaml/zipball/e7540734bad981fe59f8ef14b6fc194ae9df8d9c", + "reference": "e7540734bad981fe59f8ef14b6fc194ae9df8d9c", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3.9" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.8-dev" } }, "autoload": { - "psr-0": { + "psr-4": { "Symfony\\Component\\Yaml\\": "" - } + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -486,32 +489,26 @@ "authors": [ { "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org/", - "role": "Lead Developer" + "email": "fabien@symfony.com" }, { "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" + "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Yaml Component", - "homepage": "http://symfony.com/", - "time": "2014-05-16 14:25:18" + "homepage": "https://symfony.com/", + "time": "2016-09-02 01:57:56" } ], - "aliases": [ - - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": [ - - ], + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, "platform": { "php": ">=5.3.0", "ext-pcntl": "*" }, - "platform-dev": [ - - ] + "platform-dev": [] } From 6728b2e78fcfb0f657266b613704a70716ce9fdc Mon Sep 17 00:00:00 2001 From: Serghei Iakovlev Date: Sun, 16 Oct 2016 18:54:44 +0300 Subject: [PATCH 191/194] [Travis] Test on PHP 7.1 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 8a18b81e..9bb4841d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: php php: - 5.6 - 7.0 + - 7.1 - hhvm matrix: exclude: From b054df780fdedb5509cb3c675198e1887177a4a6 Mon Sep 17 00:00:00 2001 From: Petr Kotek Date: Thu, 20 Oct 2016 23:58:23 +0200 Subject: [PATCH 192/194] Resque_Redis: use `&&` rather than `and` --- lib/Resque/Redis.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Resque/Redis.php b/lib/Resque/Redis.php index 3b6b643f..153bd40e 100644 --- a/lib/Resque/Redis.php +++ b/lib/Resque/Redis.php @@ -98,7 +98,7 @@ class Resque_Redis */ public static function prefix($namespace) { - if (substr($namespace, -1) !== ':' and $namespace != '') { + if (substr($namespace, -1) !== ':' && $namespace != '') { $namespace .= ':'; } self::$defaultNamespace = $namespace; From 7c9c18352c9a0f9da391dc1efd8a2fabe9d2f29b Mon Sep 17 00:00:00 2001 From: lixiangyang Date: Mon, 24 Oct 2016 13:53:58 +0800 Subject: [PATCH 193/194] =?UTF-8?q?bin/resque=20=E7=BC=BA=E5=B0=91?= =?UTF-8?q?=E4=B8=80=E4=B8=AA$?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/resque | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/resque b/bin/resque index b445dd2b..1d604851 100755 --- a/bin/resque +++ b/bin/resque @@ -96,7 +96,7 @@ if(!empty($PREFIX)) { if($count > 1) { for($i = 0; $i < $count; ++$i) { $pid = Resque::fork(); - if($pid === false || pid === -1) { + if($pid === false || $pid === -1) { $logger->log(Psr\Log\LogLevel::EMERGENCY, 'Could not fork worker {count}', array('count' => $i)); die(); } @@ -126,4 +126,4 @@ else { $logger->log(Psr\Log\LogLevel::NOTICE, 'Starting worker {worker}', array('worker' => $worker)); $worker->work($interval, $BLOCKING); } -?> \ No newline at end of file +?> From da25ae12637b7c3895ebd85209ebf0754fb66bcd Mon Sep 17 00:00:00 2001 From: dinbrca Date: Tue, 6 Dec 2016 14:05:43 +0200 Subject: [PATCH 194/194] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 28a0bf58..b12fa291 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "php": ">=5.3.0", "ext-pcntl": "*", "colinmollenhour/credis": "~1.7", - "psr/log": "1.0.0" + "psr/log": "~1.0" }, "suggest": { "ext-proctitle": "Allows php-resque to rename the title of UNIX processes to show the status of a worker.",