Compare commits

...

28 commits
1.4.5 ... main

Author SHA1 Message Date
aad9334fba
2.5.3 - Update LOG()
Some checks failed
CI / Linter (push) Has been cancelled
CI / PHPTest (8.1) (push) Has been cancelled
CI / PHPTest (8.2) (push) Has been cancelled
CI / PHPTest (8.3) (push) Has been cancelled
CI / PHPTest (8.4) (push) Has been cancelled
2025-06-08 15:20:22 +12:00
b9042358e1
v2.5.2 add support for psr/log ^1 2025-06-08 14:21:33 +12:00
eb3395645f
v2.5.1 - Update psr/log reqs
Some checks are pending
CI / Linter (push) Waiting to run
CI / PHPTest (8.1) (push) Waiting to run
CI / PHPTest (8.2) (push) Waiting to run
CI / PHPTest (8.3) (push) Waiting to run
CI / PHPTest (8.4) (push) Waiting to run
2025-06-08 13:59:27 +12:00
e3ac97920c
v2.5.0 - Update packages/docs 2025-06-08 13:49:16 +12:00
81fe761577 v3.4.0 - Update packages 2024-12-11 14:31:58 +13:00
2c995bd613
v2.3.0 - Update packages 2024-09-04 18:50:32 +12:00
5ef4a63a6e
2.2.0 (2023-03-20)
- Update pacakges
- Bump requirements to PHP >= 8.1
2024-03-20 19:03:55 +13:00
948b758a57
2.1.3 (2023-11-15)
- Resolved issue with SET EX TTL's using unix-timestamps
2023-11-15 09:52:10 +13:00
Daniel Mason
0b925b68bd
Merge pull request #1 from idanoo/action_test
2.1.2 (2023-03-22) - Composer update / Update git information (GitHub)
2023-03-22 12:13:26 +13:00
575509ff53 2.1.2 (2023-03-22)
- Update composer packages
- Update git information (GitHub)
2023-03-22 12:10:33 +13:00
c696723fd0 Fix linter 2023-03-20 10:46:18 +13:00
6737df5925 Add sleep for tests 2023-03-20 10:44:47 +13:00
94cae8d271 2.1.1 (2023-03-20) - Update setex to set, add TTL to stats 2023-03-20 09:26:45 +13:00
679394eb5f
- Add PHP 8.1 / 8.2 unit tests
- Updated code to be PHP 8.2 compliant
2023-02-07 15:20:03 +13:00
3c7e20e364 2.1.0 (2023-02-07) - PHP 8.2 compatibility 2023-02-07 02:19:09 +00:00
ef82313d4e
Update 2023-02-07 14:34:41 +13:00
ba52eb34c7
Update gitlab CI 2023-02-07 14:26:15 +13:00
6458563051
Unit test PHP8.2 2023-02-07 14:18:40 +13:00
05cae402b5
2.0.3 (2022-09-12)
- Update composer packages
- Added WoodpeckerCI tests
- Updated links in composer package
- Stricter typing
2022-09-12 19:50:02 +12:00
f9a22e7b8a Bump resque version constant 2022-02-15 10:53:18 +13:00
655273ce78 Merge branch 'dev-2.0.2' into 'master'
2.0.2 (2022-02-15)

See merge request idanoo/php-resque!2
2022-02-14 21:36:34 +00:00
ac044747aa 2.0.2 (2022-02-15)
- Replace strftime with strtotime for PHP8.1 support
- Added processing class into proc line for easier debugging
2022-02-15 10:12:16 +13:00
3d869bf653 Merge branch 'dev-2.0.1' into 'master'
2.0.1

See merge request idanoo/php-resque!1
2022-02-08 06:33:49 +00:00
dd0bb8947f Update composer 2022-02-08 19:30:15 +13:00
80d64e79ff 2.0.0 Add namespacing + PHP8.0 support (#1)
2.0.0 (2021-02-19)

Moved to PSR-4
Namespaced codebase
Added more comments throughout
Co-Authored-By: idanoo <daniel@m2.nz>
Co-Committed-By: idanoo <daniel@m2.nz>
2021-02-19 12:23:32 +13:00
ebec2f7bf7 Merge branch 'dev' into 'master'
Update for PHP7.4 compatibility + PHPUnit 9

See merge request idanoo/php-resque!2
2020-04-10 21:59:55 +00:00
Daniel Mason
b99217f2c0 Update for PHP7.4 compatibility + UnitTests 2020-04-11 09:48:04 +12:00
Daniel Mason
493c12846a Switched IF Statement order to prevent excess calls to redis. 2020-01-10 11:35:56 +13:00
59 changed files with 2679 additions and 1854 deletions

36
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,36 @@
name: CI
on: [push]
jobs:
Linter:
runs-on: ubuntu-latest
container: php:8.2
steps:
- uses: actions/checkout@v3
- name: Install composer
run: apt-get update -yq && apt-get install git wget procps unzip -y && pecl install -o -f redis && rm -rf /tmp/pear && docker-php-ext-enable redis && wget https://getcomposer.org/composer.phar && php composer.phar install --dev
- name: Validate composer.json and composer.lock
run: php composer.phar validate --strict
- name: Install dependencies
run: php composer.phar install --dev --prefer-dist --no-progress
- name: Run PHPCS Linter
run: php -d memory_limit=256M vendor/bin/phpcs -s --standard=ruleset.xml
PHPTest:
runs-on: ubuntu-latest
container: php:${{ matrix.php_version }}
strategy:
matrix:
php_version: [8.1, 8.2,8.3,8.4]
services:
redis:
image: redis:7.0
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v3
- name: Install composer
run: apt-get update -yq && apt-get install git wget procps unzip -y && pecl install -o -f redis && rm -rf /tmp/pear && docker-php-ext-enable redis && wget https://getcomposer.org/composer.phar && php composer.phar install --dev
- name: Run PHP ${{ matrix.php_version }}} Unit Tests
run: php vendor/bin/phpunit --verbose --configuration phpunit.xml

3
.gitignore vendored
View file

@ -1,3 +1,2 @@
vendor/ vendor/
phpunit.xml .phpunit.result.cache
*.swp

View file

@ -4,68 +4,40 @@
# Install git (the php image doesn't have it) which is required by composer # Install git (the php image doesn't have it) which is required by composer
apt-get update -yq apt-get update -yq
apt-get install git wget procps -y apt-get install git wget procps unzip -y
# Install pcntl and redis extentions # Install pcntl and redis extentions
pecl install -o -f redis \ pecl install -o -f redis \
&& rm -rf /tmp/pear \ && rm -rf /tmp/pear \
&& docker-php-ext-enable redis && docker-php-ext-enable redis
docker-php-ext-install pcntl docker-php-ext-install pcntl
# Hack to fix mismatched php versions
rm composer.lock
# Install Composer # Install Composer
wget https://getcomposer.org/composer.phar wget https://getcomposer.org/composer.phar
php composer.phar install php composer.phar install --dev
services: services:
- redis:latest - redis:7
# Test PHP 7.0 # Test PHP
test:7.0: test:
image: php:7.0 image: php:$PHP_VERSION
parallel:
matrix:
- PHP_VERSION: [ "7.4", "8.0", "8.1", "8.2" ]
before_script: before_script:
- *docker_boostrap - *docker_boostrap
script: script:
- curl --location --output /usr/local/bin/phpunit https://phar.phpunit.de/phpunit-6.5.9.phar - php vendor/bin/phpunit --verbose --configuration phpunit.xml
- chmod +x /usr/local/bin/phpunit
- phpunit --verbose --configuration phpunit.xml.dist
tags: tags:
- docker - docker
# Test PHP 7.1 # Codestandards
test:7.1: lint:
image: php:7.1 image: php:8.2
before_script: allow_failure: true
- *docker_boostrap
script: script:
- curl --location --output /usr/local/bin/phpunit https://phar.phpunit.de/phpunit-7.5.9.phar - apt update && apt install -y wget unzip git
- chmod +x /usr/local/bin/phpunit - wget https://getcomposer.org/composer.phar
- phpunit --verbose --configuration phpunit.xml.dist - php composer.phar install --dev
tags: - php -d memory_limit=256M vendor/bin/phpcs -s --standard=ruleset.xml
- docker
# Test PHP 7.2
test:7.2:
image: php:7.2
before_script:
- *docker_boostrap
script:
- curl --location --output /usr/local/bin/phpunit https://phar.phpunit.de/phpunit-7.5.9.phar
- chmod +x /usr/local/bin/phpunit
- phpunit --verbose --configuration phpunit.xml.dist
tags:
- docker
# Test PHP 7.3
test:7.3:
image: php:7.3
before_script:
- *docker_boostrap
script:
- curl --location --output /usr/local/bin/phpunit https://phar.phpunit.de/phpunit.phar
- chmod +x /usr/local/bin/phpunit
- phpunit --verbose --configuration phpunit.xml.dist
tags:
- docker

View file

@ -1,13 +0,0 @@
language: php
php:
- 7.0
- 7.1
- 7.2
services:
- redis-server
before_script:
- echo "extension = redis.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- composer install

View file

@ -1,3 +1,67 @@
# 2.5.3 (2025-06-08)
- Update typing of Log() to support all psr\log versions
- # 2.5.2 (2025-06-08)
- Update typing of Log() to support all psr\log versions
# 2.5.1 (2025-06-08)
- Update psr/log version requirements
# 2.5.0 (2025-06-08)
- Update packages
# 2.4.0 (2024-12-11)
- Update packages (psr/log ^3.0.2)
# 2.3.0 (2024-09-04)
- Update packages
# 2.2.0 (2023-03-20)
- Update pacakges
- Bump requirements to PHP >= 8.1
# 2.1.3 (2023-11-15)
- Resolved issue with SET EX TTL's using unix-timestamps
# 2.1.2 (2023-03-22)
- Update composer packages
- Update git information (GitHub)
# 2.1.1 (2023-03-20)
- Changed setex to set with EX values
- Added TTLs to missing keys
## 2.1.0 (2023-02-07)
- Add PHP 8.1 / 8.2 unit tests
- Updated code to be PHP 8.2 compliant
## 2.0.3 (2022-09-12)
- Update composer packages
- Added WoodpeckerCI tests
- Updated links in composer package
- Stricter typing
## 2.0.2 (2022-02-15)
- Replace strftime with strtotime for PHP8.1 support
- Added processing class into proc line for easier debugging
## 2.0.1 (2022-02-08)
- Fixed issue with lingering keys causing constant memory growth
- Add PHP8 support
- Composer upgrade
## 2.0.0 (2021-02-19)
- Moved to PSR-4
- Namespaced codebase
- Added more comments throughout
## 1.4.7 (2020-04-11)
- Update PHPUnit to 9
- Start adding return types
## 1.4.6 (2020-01-10)
- Switched IF Statement order to prevent excess calls to redis.
## 1.4.5 (2019-08-28) ## 1.4.5 (2019-08-28)
- Added 'replaced' composer tag. - Added 'replaced' composer tag.
- Formatting changes. - Formatting changes.
@ -86,7 +150,7 @@ Changes by iskandar introduce improved support for using DSNs to connect to Redi
* Pass queue name to afterEvent callback * Pass queue name to afterEvent callback
* Only declare RedisException if it doesn't already exist (Matt Heath) * Only declare RedisException if it doesn't already exist (Matt Heath)
* Add support for Composer * Add support for Composer
* Fix missing and incorrect paths for Resque and Resque_Job_Status classes in demo (jjfrey) * Fix missing and incorrect paths for Resque and \Resque\Job\Status classes in demo (jjfrey)
* Disable autoload for the RedisException class_exists call (scragg0x) * Disable autoload for the RedisException class_exists call (scragg0x)
* General tidy up of comments and files/folders * General tidy up of comments and files/folders

View file

@ -14,9 +14,9 @@ What happens when you call `Resque::enqueue()`?
4. `Resque_Job::create()` pushes the job to the requested queue (first 4. `Resque_Job::create()` pushes the job to the requested queue (first
argument) argument)
5. `Resque_Job::create()`, if status monitoring is enabled for the job (fourth 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), calls `\Resque\Job\Status::create()` with the job ID as its only
argument argument
6. `Resque_Job_Status::create()` creates a key in Redis with the job ID in its 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 name, and the current status (as well as a couple of timestamps) as its
value, then returns control to `Resque_Job::create()` value, then returns control to `Resque_Job::create()`
7. `Resque_Job::create()` returns control to `Resque::enqueue()`, with the job 7. `Resque_Job::create()` returns control to `Resque::enqueue()`, with the job
@ -85,15 +85,15 @@ How do the workers process the queues?
* Worker * Worker
1. The worker waits for the job process to complete 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 2. If the exit status is not 0, the worker calls `Resque_Job->fail()` with
a `Resque_Job_DirtyExitException` as its only argument. a `Resque\Job\DirtyExitException` as its only argument.
3. `Resque_Job->fail()` triggers an `onFailure` event 3. `Resque_Job->fail()` triggers an `onFailure` event
4. `Resque_Job->fail()` updates the job status from `RUNNING` to `FAILED` 4. `Resque_Job->fail()` updates the job status from `RUNNING` to `FAILED`
5. `Resque_Job->fail()` calls `Resque_Failure::create()` with the job 5. `Resque_Job->fail()` calls `Resque_Failure::create()` with the job
payload, the `Resque_Job_DirtyExitException`, the internal ID of the payload, the `Resque\Job\DirtyExitException`, the internal ID of the
worker, and the queue name as arguments worker, and the queue name as arguments
6. `Resque_Failure::create()` creates a new object of whatever type has 6. `Resque_Failure::create()` creates a new object of whatever type has
been set as the `Resque_Failure` "backend" handler; by default, this is been set as the `Resque_Failure` "backend" handler; by default, this is
a `Resque_Failure_Redis` object, whose constructor simply collects the a `ResqueFailureRedis` object, whose constructor simply collects the
data passed into `Resque_Failure::create()` and pushes it into Redis data passed into `Resque_Failure::create()` and pushes it into Redis
in the `failed` queue in the `failed` queue
7. `Resque_Job->fail()` increments two failure counters in Redis: one for 7. `Resque_Job->fail()` increments two failure counters in Redis: one for

View file

@ -1,4 +1,4 @@
php-resque: PHP Resque Worker (and Enqueue) php-resque: PHP Background (Resque) Worker
=========================================== ===========================================
Resque is a Redis-backed library for creating background jobs, placing Resque is a Redis-backed library for creating background jobs, placing
@ -42,7 +42,7 @@ On top of the original fork (chrisboulton/php-resque) I have added:
## Requirements ## ## Requirements ##
* PHP 7.0+ * PHP 8.1+
* phpredis * phpredis
* Redis 2.2+ * Redis 2.2+
@ -53,19 +53,9 @@ Composer package inside your project.
If you're not familiar with Composer, please see <http://getcomposer.org/>. If you're not familiar with Composer, please see <http://getcomposer.org/>.
1. Add php-resque to your application's composer.json. 1. Run `composer require idanoo/php-resque`.
```json 2. If you haven't already, add the Composer autoload to your project's
{
"require": {
"idanoo/php-resque": "^1.4"
}
}
```
2. Run `composer install`.
3. If you haven't already, add the Composer autoload to your project's
initialization file. (example) initialization file. (example)
```sh ```sh
@ -80,11 +70,11 @@ Jobs are queued as follows:
```php ```php
// Required if redis is located elsewhere // Required if redis is located elsewhere
Resque::setBackend('localhost:6379'); Resque::setBackend('redis:6379');
$args = ['name' => 'TestName']; $args = ['name' => 'TestName'];
Resque::enqueue('default', 'My_Job', $args); Resque::enqueue('default', '\App\MyJobClass', $args);
``` ```
### Defining Jobs ### ### Defining Jobs ###
@ -92,7 +82,9 @@ Resque::enqueue('default', 'My_Job', $args);
Each job should be in its own class, and include a `perform` method. Each job should be in its own class, and include a `perform` method.
```php ```php
class My_Job namespace \App;
class MyJobClass
{ {
public function perform() public function perform()
{ {
@ -115,7 +107,9 @@ The `tearDown` method, if defined, will be called after the job finishes.
```php ```php
class My_Job namespace App;
class MyJobClass
{ {
public function setUp() public function setUp()
{ {
@ -139,17 +133,17 @@ class My_Job
This method can be used to conveniently remove a job from a queue. This method can be used to conveniently remove a job from a queue.
```php ```php
// Removes job class 'My_Job' of queue 'default' // Removes job class '\App\MyJobClass' of queue 'default'
Resque::dequeue('default', ['My_Job']); Resque::dequeue('default', ['\App\MyJobClass']);
// Removes job class 'My_Job' with Job ID '087df5819a790ac666c9608e2234b21e' of queue 'default' // Removes job class '\App\MyJobClass' with Job ID '087df5819a790ac666c9608e2234b21e' of queue 'default'
Resque::dequeue('default', ['My_Job' => '087df5819a790ac666c9608e2234b21e']); Resque::dequeue('default', ['\App\MyJobClass' => '087df5819a790ac666c9608e2234b21e']);
// Removes job class 'My_Job' with arguments of queue 'default' // Removes job class '\App\MyJobClass' with arguments of queue 'default'
Resque::dequeue('default', ['My_Job' => ['foo' => 1, 'bar' => 2]]); Resque::dequeue('default', ['\App\MyJobClass' => ['foo' => 1, 'bar' => 2]]);
// Removes multiple jobs // Removes multiple jobs
Resque::dequeue('default', ['My_Job', 'My_Job2']); Resque::dequeue('default', ['\App\MyJobClass', '\App\MyJobClass2']);
``` ```
If no jobs are given, this method will dequeue all jobs matching the provided queue. If no jobs are given, this method will dequeue all jobs matching the provided queue.
@ -170,7 +164,7 @@ To track the status of a job, pass `true` as the fourth argument to
returned: returned:
```php ```php
$token = Resque::enqueue('default', 'My_Job', $args, true); $token = Resque::enqueue('default', '\App\MyJobClass', $args, true);
echo $token; echo $token;
``` ```
@ -367,8 +361,6 @@ 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 for operation. If you have rolled your own worker manager, then it is again your
responsibility to register listeners. responsibility to register listeners.
A sample plugin is included in the `extras` directory.
### Events ### ### Events ###
#### beforeFirstFork #### #### beforeFirstFork ####
@ -470,7 +462,7 @@ needing to directly examine the code), have a look at `HOWITWORKS.md`.
## Contributors ## ## Contributors ##
### Current Maintainers ### ### Current Maintainers ###
* @iDanoo * @idanoo
### Past Maintainer / Forked From ### ### Past Maintainer / Forked From ###

View file

@ -9,7 +9,6 @@ $files = [
__DIR__ . '/../vendor/autoload.php', __DIR__ . '/../vendor/autoload.php',
]; ];
$found = false;
foreach ($files as $file) { foreach ($files as $file) {
if (file_exists($file)) { if (file_exists($file)) {
require_once $file; require_once $file;
@ -25,6 +24,7 @@ if (!class_exists('Composer\Autoload\ClassLoader', false)) {
); );
} }
// Set which queues to monitor '*'
$QUEUE = getenv('QUEUE'); $QUEUE = getenv('QUEUE');
if (empty($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");
@ -38,22 +38,26 @@ if (empty($QUEUE)) {
*/ */
$REDIS_BACKEND = getenv('REDIS_BACKEND'); $REDIS_BACKEND = getenv('REDIS_BACKEND');
// A redis database number /**
* REDIS_BACKEND_DB overrides default Redis DB
*/
$REDIS_BACKEND_DB = getenv('REDIS_BACKEND_DB'); $REDIS_BACKEND_DB = getenv('REDIS_BACKEND_DB');
if (!empty($REDIS_BACKEND)) { if (!empty($REDIS_BACKEND)) {
if (empty($REDIS_BACKEND_DB)) { if (empty($REDIS_BACKEND_DB)) {
Resque::setBackend($REDIS_BACKEND); \Resque\Resque::setBackend($REDIS_BACKEND);
} else { } else {
Resque::setBackend($REDIS_BACKEND, $REDIS_BACKEND_DB); \Resque\Resque::setBackend($REDIS_BACKEND, $REDIS_BACKEND_DB);
} }
} }
// Set Logging level
$logLevel = false; $logLevel = false;
$LOGGING = getenv('LOGLEVEL'); $LOGGING = getenv('LOGLEVEL');
if (!empty($LOGGING)) { if (!empty($LOGGING)) {
$logLevel = $LOGGING; $logLevel = $LOGGING;
} }
// Bootstrap file
$APP_INCLUDE = getenv('APP_INCLUDE'); $APP_INCLUDE = getenv('APP_INCLUDE');
if ($APP_INCLUDE) { if ($APP_INCLUDE) {
if (!file_exists($APP_INCLUDE)) { if (!file_exists($APP_INCLUDE)) {
@ -66,41 +70,45 @@ if ($APP_INCLUDE) {
// See if the APP_INCLUDE containes a logger object, // See if the APP_INCLUDE containes a logger object,
// If none exists, fallback to internal logger // If none exists, fallback to internal logger
if (!isset($logger) || !is_object($logger)) { if (!isset($logger) || !is_object($logger)) {
$logger = new Resque_Log($logLevel); $logger = new \Resque\Log($logLevel);
} }
// Determines if blocking or not
$BLOCKING = getenv('BLOCKING') !== FALSE; $BLOCKING = getenv('BLOCKING') !== FALSE;
// Interval to check for jobs
$interval = 5; $interval = 5;
$INTERVAL = getenv('INTERVAL'); $INTERVAL = getenv('INTERVAL');
if (!empty($INTERVAL)) { if (!empty($INTERVAL)) {
$interval = $INTERVAL; $interval = $INTERVAL;
} }
// Sets worker count
$count = 1; $count = 1;
$COUNT = getenv('COUNT'); $COUNT = getenv('COUNT');
if (!empty($COUNT) && $COUNT > 1) { if (!empty($COUNT) && $COUNT > 1) {
$count = $COUNT; $count = $COUNT;
} }
// Determines redis key prefix
$PREFIX = getenv('PREFIX'); $PREFIX = getenv('PREFIX');
if (!empty($PREFIX)) { if (!empty($PREFIX)) {
$logger->log(Psr\Log\LogLevel::INFO, 'Prefix set to {prefix}', ['prefix' => $PREFIX]); $logger->log(\Psr\Log\LogLevel::INFO, 'Prefix set to {prefix}', ['prefix' => $PREFIX]);
Resque_Redis::prefix($PREFIX); \Resque\Redis::prefix($PREFIX);
} }
if ($count > 1) { if ($count > 1) {
for ($i = 0; $i < $count; ++$i) { for ($i = 0; $i < $count; ++$i) {
$pid = Resque::fork(); $pid = \Resque\Resque::fork();
if ($pid === false || $pid === -1) { if ($pid === false || $pid === -1) {
$logger->log(Psr\Log\LogLevel::EMERGENCY, 'Could not fork worker {count}', ['count' => $i]); $logger->log(\Psr\Log\LogLevel::EMERGENCY, 'Could not fork worker {count}', ['count' => $i]);
die(); die();
} elseif (!$pid) { } elseif (!$pid) {
// Child, start the worker // Child, start the worker
$queues = explode(',', $QUEUE); $queues = explode(',', $QUEUE);
$worker = new Resque_Worker($queues); $worker = new \Resque\Worker($queues);
$worker->setLogger($logger); $worker->setLogger($logger);
$logger->log(Psr\Log\LogLevel::NOTICE, 'Starting worker {worker}', ['worker' => $worker]); $logger->log(\Psr\Log\LogLevel::NOTICE, 'Starting worker {worker}', ['worker' => $worker]);
$worker->work($interval, $BLOCKING); $worker->work($interval, $BLOCKING);
break; break;
} }
@ -108,7 +116,7 @@ if ($count > 1) {
} else { } else {
// Start a single worker // Start a single worker
$queues = explode(',', $QUEUE); $queues = explode(',', $QUEUE);
$worker = new Resque_Worker($queues); $worker = new \Resque\Worker($queues);
$worker->setLogger($logger); $worker->setLogger($logger);
$PIDFILE = getenv('PIDFILE'); $PIDFILE = getenv('PIDFILE');
@ -117,6 +125,6 @@ if ($count > 1) {
die('Could not write PID information to ' . $PIDFILE); die('Could not write PID information to ' . $PIDFILE);
} }
$logger->log(Psr\Log\LogLevel::NOTICE, 'Starting worker {worker}', ['worker' => $worker]); $logger->log(\Psr\Log\LogLevel::NOTICE, 'Starting worker {worker}', ['worker' => $worker]);
$worker->work($interval, $BLOCKING); $worker->work($interval, $BLOCKING);
} }

View file

@ -1,18 +0,0 @@
<!--suppress PhingDomInspection -->
<project name="php-resque" default="build">
<target name="clean">
<delete dir="${basedir}/build" />
</target>
<target name="prepare">
<mkdir dir="${basedir}/build" />
<mkdir dir="${basedir}/build/logs" />
</target>
<target name="phpunit">
<exec dir="${basedir}" executable="phpunit">
<arg line="--log-junit ${basedir}/build/logs/phpunit.xml
--coverage-clover ${basedir}/build/logs/clover.xml
--coverage-html ${basedir}/build/coverage" />
</exec>
</target>
<target name="build" depends="clean,prepare,phpunit" />
</project>

View file

@ -1,14 +1,13 @@
{ {
"name": "idanoo/php-resque", "name": "idanoo/php-resque",
"version": "1.4.5",
"type": "library", "type": "library",
"replace": { "replace": {
"chrisboulton/php-resque": "*", "chrisboulton/php-resque": "*",
"danhunsaker/php-resque": "*" "danhunsaker/php-resque": "*"
}, },
"description": "Redis backed library for creating background jobs and processing them later. Based on resque for Ruby. Originally forked from chrisboulton/php-resque.", "description": "Redis backed library for creating background jobs and processing them later. Based on resque for Ruby. Originally forked from chrisboulton/php-resque.",
"keywords": ["job", "background", "redis", "resque"], "keywords": ["job", "background", "redis", "resque", "php"],
"homepage": "http://www.github.com/idanoo/php-resque/", "homepage": "https://github.com/idanoo/php-resque",
"license": "MIT", "license": "MIT",
"authors": [ "authors": [
{ {
@ -17,25 +16,36 @@
} }
], ],
"require": { "require": {
"php": "^7.0", "php": ">=8.1",
"ext-pcntl": "*", "psr/log": "^1.1 || ^2.0 || ^3.0",
"ext-redis": "*", "colinmollenhour/credis": "^1.14.0"
"psr/log": "~1.0",
"colinmollenhour/credis": "^1.10"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^6" "phpunit/phpunit": "^9",
"squizlabs/php_codesniffer": "3.*",
"phpcompatibility/php-compatibility": "^9.3",
"dealerdirect/phpcodesniffer-composer-installer": "^1.0"
}, },
"bin": [ "bin": [
"bin/resque" "bin/resque"
], ],
"autoload": { "autoload": {
"psr-0": { "psr-4": {
"Resque": "lib" "Resque\\": "src/Resque"
}
},
"autoload-dev": {
"psr-4": {
"Resque\\Test\\": "tests/Resque/Tests"
} }
}, },
"support": { "support": {
"issues": "https://github.com/idanoo/php-resque/issues", "issues": "https://github.com/idanoo/php-resque/issues",
"source": "https://github.com/idanoo/php-resque" "source": "https://github.com/idanoo/php-resque"
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
} }
} }

1676
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,8 +0,0 @@
<?php
class Bad_PHP_Job
{
public function perform()
{
throw new Exception('Unable to run this job!');
}
}

View file

@ -1,9 +0,0 @@
<?php /** @noinspection PhpUndefinedFunctionInspection */
class PHP_Error_Job
{
public function perform()
{
callToUndefinedFunction();
}
}

View file

@ -1,7 +0,0 @@
<?php
date_default_timezone_set('GMT');
require 'bad_job.php';
require 'job.php';
require 'php_error_job.php';
require '../bin/resque';

11
examples/BadPHPJob.php Normal file
View file

@ -0,0 +1,11 @@
<?php
namespace Resque\Example;
class BadPHPJob
{
public function perform()
{
throw new \Exception('Unable to run this job!');
}
}

View file

@ -1,4 +1,7 @@
<?php <?php
namespace Resque\Example;
if (empty($argv[1])) { if (empty($argv[1])) {
die('Specify the ID of a job to monitor the status of.'); die('Specify the ID of a job to monitor the status of.');
} }
@ -6,12 +9,12 @@ if (empty($argv[1])) {
require __DIR__ . '/init.php'; require __DIR__ . '/init.php';
date_default_timezone_set('GMT'); date_default_timezone_set('GMT');
Resque::setBackend('127.0.0.1:6379'); \Resque\Resque::setBackend('127.0.0.1:6379');
// You can also use a DSN-style format: // You can also use a DSN-style format:
//Resque::setBackend('redis://user:pass@127.0.0.1:6379'); //Resque::setBackend('redis://user:pass@127.0.0.1:6379');
//Resque::setBackend('redis://user:pass@a.host.name:3432/2'); //Resque::setBackend('redis://user:pass@a.host.name:3432/2');
$status = new Resque_Job_Status($argv[1]); $status = new \Resque\Job\Status($argv[1]);
if (!$status->isTracking()) { if (!$status->isTracking()) {
die("Resque is not tracking the status of this job.\n"); die("Resque is not tracking the status of this job.\n");
} }
@ -20,4 +23,4 @@ echo "Tracking status of " . $argv[1] . ". Press [break] to stop.\n\n";
while (true) { while (true) {
fwrite(STDOUT, "Status of " . $argv[1] . " is: " . $status->get() . "\n"); fwrite(STDOUT, "Status of " . $argv[1] . " is: " . $status->get() . "\n");
sleep(1); sleep(1);
} }

View file

@ -1,4 +1,7 @@
<?php <?php
namespace Resque\Example;
// Find and initialize Composer // Find and initialize Composer
// NOTE: You should NOT use this when developing against php-resque. // NOTE: You should NOT use this when developing against php-resque.
// The autoload code below is specifically for this demo. // The autoload code below is specifically for this demo.
@ -8,7 +11,6 @@ $files = [
__DIR__ . '/../vendor/autoload.php', __DIR__ . '/../vendor/autoload.php',
]; ];
$found = false;
foreach ($files as $file) { foreach ($files as $file) {
if (file_exists($file)) { if (file_exists($file)) {
require_once $file; require_once $file;
@ -22,4 +24,4 @@ if (!class_exists('Composer\Autoload\ClassLoader', false)) {
'curl -s http://getcomposer.org/installer | php' . PHP_EOL . 'curl -s http://getcomposer.org/installer | php' . PHP_EOL .
'php composer.phar install' . PHP_EOL 'php composer.phar install' . PHP_EOL
); );
} }

View file

@ -1,9 +1,11 @@
<?php <?php
class Long_PHP_Job namespace Resque\Example;
class LongPHPJob
{ {
public function perform() public function perform()
{ {
sleep(600); sleep(600);
} }
} }

13
examples/PHPErrorJob.php Normal file
View file

@ -0,0 +1,13 @@
<?php
/** @noinspection PhpUndefinedFunctionInspection */
namespace Resque\Example;
class PHPErrorJob
{
public function perform()
{
callToUndefinedFunction();
}
}

View file

@ -1,6 +1,8 @@
<?php <?php
class PHP_Job namespace Resque\Example;
class PHPJob
{ {
public function perform() public function perform()
{ {
@ -8,4 +10,4 @@ class PHP_Job
sleep(1); sleep(1);
fwrite(STDOUT, 'Job ended!' . PHP_EOL); fwrite(STDOUT, 'Job ended!' . PHP_EOL);
} }
} }

View file

@ -1,14 +1,17 @@
<?php <?php
// Somewhere in our application, we need to register:
Resque_Event::listen('afterEnqueue', ['My_Resque_Plugin', 'afterEnqueue']);
Resque_Event::listen('beforeFirstFork', ['My_Resque_Plugin', 'beforeFirstFork']);
Resque_Event::listen('beforeFork', ['My_Resque_Plugin', 'beforeFork']);
Resque_Event::listen('afterFork', ['My_Resque_Plugin', 'afterFork']);
Resque_Event::listen('beforePerform', ['My_Resque_Plugin', 'beforePerform']);
Resque_Event::listen('afterPerform', ['My_Resque_Plugin', 'afterPerform']);
Resque_Event::listen('onFailure', ['My_Resque_Plugin', 'onFailure']);
class Sample_Resque_Plugin namespace Resque\Example;
// Somewhere in our application, we need to register:
// \Resque\Event::listen('afterEnqueue', ['My_Resque_Plugin', 'afterEnqueue']);
// \Resque\Event::listen('beforeFirstFork', ['My_Resque_Plugin', 'beforeFirstFork']);
// \Resque\Event::listen('beforeFork', ['My_Resque_Plugin', 'beforeFork']);
// \Resque\Event::listen('afterFork', ['My_Resque_Plugin', 'afterFork']);
// \Resque\Event::listen('beforePerform', ['My_Resque_Plugin', 'beforePerform']);
// \Resque\Event::listen('afterPerform', ['My_Resque_Plugin', 'afterPerform']);
// \Resque\Event::listen('onFailure', ['My_Resque_Plugin', 'onFailure']);
class SampleResquePlugin
{ {
public static function afterEnqueue($class, $arguments) public static function afterEnqueue($class, $arguments)
{ {
@ -34,7 +37,7 @@ class Sample_Resque_Plugin
public static function beforePerform($job) public static function beforePerform($job)
{ {
echo "Cancelling " . $job . "\n"; echo "Cancelling " . $job . "\n";
// throw new Resque_Job_DontPerform; // throw new Resque_Job_DontPerform;
} }
public static function afterPerform($job) public static function afterPerform($job)
@ -46,4 +49,4 @@ class Sample_Resque_Plugin
{ {
echo $job . " threw an exception:\n" . $exception; echo $job . " threw an exception:\n" . $exception;
} }
} }

View file

@ -1,11 +1,14 @@
<?php <?php
namespace Resque\Example;
if (empty($argv[1])) { if (empty($argv[1])) {
die('Specify the name of a job to add. e.g, php queue.php PHP_Job'); die('Specify the name of a job to add. e.g, php queue.php PHPJob');
} }
require __DIR__ . '/init.php'; require __DIR__ . '/init.php';
date_default_timezone_set('GMT'); date_default_timezone_set('GMT');
Resque::setBackend('127.0.0.1:6379'); \Resque\Resque::setBackend('127.0.0.1:6379');
// You can also use a DSN-style format: // You can also use a DSN-style format:
//Resque::setBackend('redis://user:pass@127.0.0.1:6379'); //Resque::setBackend('redis://user:pass@127.0.0.1:6379');
@ -18,9 +21,9 @@ $args = [
], ],
]; ];
if (empty($argv[2])) { if (empty($argv[2])) {
$jobId = Resque::enqueue('default', $argv[1], $args, true); $jobId = \Resque\Resque::enqueue('default', $argv[1], $args, true);
} else { } else {
$jobId = Resque::enqueue($argv[1], $argv[2], $args, true); $jobId = \Resque\Resque::enqueue($argv[1], $argv[2], $args, true);
} }
echo "Queued job " . $jobId . "\n\n"; echo "Queued job " . $jobId . "\n\n";

View file

@ -5,6 +5,6 @@
compress compress
compressoptions -4 compressoptions -4
notifempty notifempty
create 640 root adm create 640 root www-data
copytruncate copytruncate
} }

View file

@ -1,15 +0,0 @@
# Borrowed with modifications from
# https://github.com/defunkt/resque/blob/master/examples/monit/resque.monit
# Replace these with your own:
# [QUEUE]
# [PATH/TO/RESQUE]
# [UID]
# [GID]
# [APP_INCLUDE]
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]/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

View file

@ -1,32 +0,0 @@
<?php
class Resque_Job_Factory implements Resque_Job_FactoryInterface
{
/**
* @param $className
* @param array $args
* @param $queue
* @return Resque_JobInterface
* @throws Resque_Exception
*/
public function create($className, $args, $queue)
{
if (!class_exists($className)) {
throw new Resque_Exception(
'Could not find job class ' . $className . '.'
);
}
if (!method_exists($className, 'perform')) {
throw new Resque_Exception(
'Job class ' . $className . ' does not contain a perform method.'
);
}
$instance = new $className;
$instance->args = $args;
$instance->queue = $queue;
return $instance;
}
}

View file

@ -1,12 +0,0 @@
<?php
interface Resque_Job_FactoryInterface
{
/**
* @param $className
* @param array $args
* @param $queue
* @return Resque_JobInterface
*/
public function create($className, $args, $queue);
}

View file

@ -1,14 +0,0 @@
<?php
/**
* Redis related exceptions
*
* @package Resque
* @author Chris Boulton <chris@bigcommerce.com>
* @license http://www.opensource.org/licenses/mit-license.php
*/
class Resque_RedisException extends Resque_Exception
{
}

View file

@ -1,24 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false" <phpunit backupGlobals="false"
bootstrap="test/bootstrap.php" bootstrap="tests/bootstrap.php"
backupStaticAttributes="false" backupStaticAttributes="false"
colors="true" colors="true"
convertErrorsToExceptions="true" convertErrorsToExceptions="true"
convertNoticesToExceptions="true" convertNoticesToExceptions="true"
convertWarningsToExceptions="true" convertWarningsToExceptions="true"
processIsolation="false" processIsolation="true"
stopOnFailure="false" stopOnFailure="false"
syntaxCheck="false"
> >
<testsuites> <testsuites>
<testsuite name="Resque Test Suite"> <testsuite name="Resque Test Suite">
<directory>./test/Resque/</directory> <directory>./tests/Resque/</directory>
</testsuite> </testsuite>
</testsuites> </testsuites>
<filter>
<whitelist>
<directory suffix=".php">./lib/Resque/</directory>
</whitelist>
</filter>
</phpunit> </phpunit>

29
ruleset.xml Normal file
View file

@ -0,0 +1,29 @@
<?xml version="1.0"?>
<ruleset name="PHP82" namespace="ezyVet\PHPCS">
<description>PHP8.2 Ruleset</description>
<file>.</file>
<exclude-pattern>vendor</exclude-pattern>
<exclude-pattern>tests/</exclude-pattern>
<arg name="extensions" value="php" />
<arg name="colors"/>
<arg value="sp"/>
<arg name="parallel" value="16"/>
<arg name="report-width" value="140" />
<arg name="error-severity" value="1" />
<!-- Setting warning-severity here overrides both the '-n' CLI option and 'config-set show_warnings 0', so we
can't use it. -->
<ini name="memory_limit" value="256M"/>
<!-- Check for version support for PHP 8.2 and higher. -->
<config name="testVersion" value="8.2-"/>
<rule ref="PSR12">
</rule>
<rule ref="PHPCompatibility">
</rule>
</ruleset>

View file

@ -1,14 +1,16 @@
<?php <?php
namespace Resque;
/** /**
* Resque event/plugin system class * Resque event/plugin system class
* *
* @package Resque/Event * @package Resque/Event
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Event class Event
{ {
/** /**
* @var array Array containing all registered callbacks, indexked by event name. * @var array Array containing all registered callbacks, indexked by event name.
@ -20,6 +22,7 @@ class Resque_Event
* *
* @param string $event Name of event to be raised. * @param string $event Name of event to be raised.
* @param mixed $data Optional, any data that should be passed to each callback. * @param mixed $data Optional, any data that should be passed to each callback.
*
* @return true * @return true
*/ */
public static function trigger($event, $data = null) public static function trigger($event, $data = null)
@ -36,7 +39,8 @@ class Resque_Event
if (!is_callable($callback)) { if (!is_callable($callback)) {
continue; continue;
} }
call_user_func_array($callback, $data);
call_user_func_array($callback, array_values($data));
} }
return true; return true;
@ -46,7 +50,8 @@ class Resque_Event
* Listen in on a given event to have a specified callback fired. * Listen in on a given event to have a specified callback fired.
* *
* @param string $event Name of event to listen on. * @param string $event Name of event to listen on.
* @param mixed $callback Any callback callable by call_user_func_array. * @param mixed $callback Any callback callable by call_user_func_array
*
* @return true * @return true
*/ */
public static function listen($event, $callback) public static function listen($event, $callback)
@ -64,6 +69,7 @@ class Resque_Event
* *
* @param string $event Name of event. * @param string $event Name of event.
* @param mixed $callback The callback as defined when listen() was called. * @param mixed $callback The callback as defined when listen() was called.
*
* @return true * @return true
*/ */
public static function stopListening($event, $callback) public static function stopListening($event, $callback)
@ -82,8 +88,10 @@ class Resque_Event
/** /**
* Call all registered listeners. * Call all registered listeners.
*
* @return void
*/ */
public static function clearListeners() public static function clearListeners(): void
{ {
self::$events = []; self::$events = [];
} }

View file

@ -1,13 +1,15 @@
<?php <?php
namespace Resque;
/** /**
* Resque exception. * Resque exception.
* *
* @package Resque * @package Resque
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Exception extends Exception class Exception extends \Exception
{ {
} }

View file

@ -1,14 +1,16 @@
<?php <?php
namespace Resque\Failure;
/** /**
* Failed Resque job. * Failed Resque job.
* *
* @package Resque/Failure * @package Resque/Failure
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Failure class Failure
{ {
/** /**
* @var string Class name representing the backend to pass failed jobs off to. * @var string Class name representing the backend to pass failed jobs off to.
@ -19,12 +21,16 @@ class Resque_Failure
* Create a new failed job on the backend. * Create a new failed job on the backend.
* *
* @param array $payload The contents of the job that has just failed. * @param array $payload The contents of the job that has just failed.
* @param Exception $exception The exception generated when the job failed to run. * @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 \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. * @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) public static function create(
{ $payload,
\Exception $exception,
\Resque\Worker $worker,
$queue
) {
$backend = self::getBackend(); $backend = self::getBackend();
new $backend($payload, $exception, $worker, $queue); new $backend($payload, $exception, $worker, $queue);
} }
@ -32,12 +38,12 @@ class Resque_Failure
/** /**
* Return an instance of the backend for saving job failures. * Return an instance of the backend for saving job failures.
* *
* @return object|string * @return string
*/ */
public static function getBackend() public static function getBackend()
{ {
if (self::$backend === null) { if (is_null(self::$backend)) {
self::$backend = 'Resque_Failure_Redis'; self::$backend = '\\Resque\\Failure\\ResqueFailureRedis';
} }
return self::$backend; return self::$backend;
@ -49,9 +55,11 @@ class Resque_Failure
* It is your responsibility to have the backend class loaded (or autoloaded) * It is your responsibility to have the backend class loaded (or autoloaded)
* *
* @param string $backend The class name of the backend to pipe failures to. * @param string $backend The class name of the backend to pipe failures to.
*
* @return void
*/ */
public static function setBackend($backend) public static function setBackend(string $backend): void
{ {
self::$backend = $backend; self::$backend = $backend;
} }
} }

View file

@ -1,13 +1,15 @@
<?php <?php
namespace Resque\Failure;
/** /**
* Interface that all failure backends should implement. * Interface that all failure backends should implement.
* *
* @package Resque/Failure * @package Resque\Failure
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
interface Resque_Failure_Interface interface ResqueFailureInterface
{ {
/** /**
* Initialize a failed job class and save it (where appropriate). * Initialize a failed job class and save it (where appropriate).

View file

@ -1,13 +1,16 @@
<?php <?php
namespace Resque\Failure;
/** /**
* Redis backend for storing failed Resque jobs. * Redis backend for storing failed Resque jobs.
* *
* @package Resque/Failure * @package Resque\Failure
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Failure_Redis implements Resque_Failure_Interface class ResqueFailureRedis implements ResqueFailureInterface
{ {
/** /**
* Initialize a failed job class and save it (where appropriate). * Initialize a failed job class and save it (where appropriate).
@ -16,12 +19,12 @@ class Resque_Failure_Redis implements Resque_Failure_Interface
* @param object $exception Instance of the exception that was thrown by the failed job. * @param object $exception Instance of the exception that was thrown by the failed job.
* @param object $worker Instance of Resque_Worker that received the job. * @param object $worker Instance of Resque_Worker that received the job.
* @param string $queue The name of the queue the job was fetched from. * @param string $queue The name of the queue the job was fetched from.
* @throws Resque_RedisException * @throws \Resque\RedisException
*/ */
public function __construct($payload, $exception, $worker, $queue) public function __construct($payload, $exception, $worker, $queue)
{ {
$data = new stdClass; $data = new \stdClass();
$data->failed_at = strftime('%a %b %d %H:%M:%S %Z %Y'); $data->failed_at = date('D M d H:i:s T Y');
$data->payload = $payload; $data->payload = $payload;
$data->exception = get_class($exception); $data->exception = get_class($exception);
$data->error = $exception->getMessage(); $data->error = $exception->getMessage();
@ -29,6 +32,6 @@ class Resque_Failure_Redis implements Resque_Failure_Interface
$data->worker = (string)$worker; $data->worker = (string)$worker;
$data->queue = $queue; $data->queue = $queue;
$data = json_encode($data); $data = json_encode($data);
Resque::redis()->rpush('failed', $data); \Resque\Resque::redis()->rpush('failed', $data);
} }
} }

View file

@ -1,13 +1,14 @@
<?php <?php
namespace Resque\Job;
/** /**
* Runtime exception class for a job that does not exit cleanly. * Runtime exception class for a job that does not exit cleanly.
* *
* @package Resque/Job * @package Resque/Job
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Job_DirtyExitException extends RuntimeException class DirtyExitException extends \RuntimeException
{ {
} }

View file

@ -1,13 +1,14 @@
<?php <?php
namespace Resque\Job;
/** /**
* Exception to be thrown if while enqueuing a job it should not be created. * Exception to be thrown if while enqueuing a job it should not be created.
* *
* @package Resque/Job * @package Resque/Job
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Job_DontCreate extends Exception class DontCreate extends \Exception
{ {
} }

View file

@ -1,14 +1,14 @@
<?php <?php
namespace Resque\Job;
/** /**
* Exception to be thrown if a job should not be performed/run. * Exception to be thrown if a job should not be performed/run.
* *
* @package Resque/Job * @package Resque/Job
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class DontPerform extends \Exception
class Resque_Job_DontPerform extends Exception
{ {
} }

View file

@ -0,0 +1,50 @@
<?php
namespace Resque\Job;
/**
* Job Factory!
*
* @package Resque/Job
* @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php
*/
class Factory implements FactoryInterface
{
public ?Job $job;
public string $queue;
public array $args;
/**
* Create job factory
*
* @param $className
* @param array $args
* @param $queue
*
* @return \Resque\Job\JobInterface
*
* @throws \Resque\Exception
*/
public function create($className, $args, $queue)
{
if (!class_exists($className)) {
throw new \Resque\Exception(
'Could not find job class ' . $className . '.'
);
}
if (!method_exists($className, 'perform')) {
throw new \Resque\Exception(
'Job class ' . $className . ' does not contain a perform() method.'
);
}
$instance = new $className();
$instance->args = $args;
$instance->queue = $queue;
return $instance;
}
}

View file

@ -0,0 +1,22 @@
<?php
namespace Resque\Job;
/**
* Job Interface
*
* @package Resque/Job
* @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php
*/
interface FactoryInterface
{
/**
* @param $className
* @param array $args
* @param $queue
*
* @return \Resque\Job\JobInterface
*/
public function create($className, $args, $queue);
}

View file

@ -1,14 +1,16 @@
<?php <?php
namespace Resque\Job;
/** /**
* Resque job. * Resque job.
* *
* @package Resque/Job * @package Resque/Job
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Job class Job
{ {
/** /**
* @var string The name of the queue that this job belongs to. * @var string The name of the queue that this job belongs to.
@ -16,7 +18,7 @@ class Resque_Job
public $queue; public $queue;
/** /**
* @var Resque_Worker Instance of the Resque worker running this job. * @var \Resque\Worker Instance of the Resque worker running this job.
*/ */
public $worker; public $worker;
@ -26,12 +28,12 @@ class Resque_Job
public $payload; public $payload;
/** /**
* @var object|Resque_JobInterface Instance of the class performing work for this job. * @var object|\Resque\Job\JobInterface Instance of the class performing work for this job.
*/ */
private $instance; private $instance;
/** /**
* @var Resque_Job_FactoryInterface * @var \Resque\Job\FactoryInterface
*/ */
private $jobFactory; private $jobFactory;
@ -57,20 +59,21 @@ class Resque_Job
* @param string $id Unique identifier for tracking the job. Generated if not supplied. * @param string $id Unique identifier for tracking the job. Generated if not supplied.
* *
* @return string * @return string
* @throws InvalidArgumentException *
* @throws \InvalidArgumentException
*/ */
public static function create($queue, $class, $args = null, $monitor = false, $id = null) public static function create($queue, $class, $args = null, $monitor = false, $id = null): string
{ {
if (is_null($id)) { if (is_null($id)) {
$id = Resque::generateJobId(); $id = \Resque\Resque::generateJobId();
} }
if ($args !== null && !is_array($args)) { if ($args !== null && !is_array($args)) {
throw new InvalidArgumentException( throw new \InvalidArgumentException(
'Supplied $args must be an array.' 'Supplied $args must be an array.'
); );
} }
Resque::push($queue, [ \Resque\Resque::push($queue, [
'class' => $class, 'class' => $class,
'args' => [$args], 'args' => [$args],
'id' => $id, 'id' => $id,
@ -78,7 +81,7 @@ class Resque_Job
]); ]);
if ($monitor) { if ($monitor) {
Resque_Job_Status::create($id); Status::create($id);
} }
return $id; return $id;
@ -86,43 +89,47 @@ class Resque_Job
/** /**
* Find the next available job from the specified queue and return an * Find the next available job from the specified queue and return an
* instance of Resque_Job for it. * instance of \Resque\Job\Job for it.
* *
* @param string $queue The name of the queue to check for a job in. * @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. *
* @return Job|null Null when there aren't any waiting jobs, instance of \Resque\Job\Job when a job was found.
*/ */
public static function reserve($queue) public static function reserve($queue): ?Job
{ {
$payload = Resque::pop($queue); $payload = \Resque\Resque::pop($queue);
if (!is_array($payload)) { if (!is_array($payload)) {
return false; return null;
} }
return new Resque_Job($queue, $payload); return new Job($queue, $payload);
} }
/** /**
* Find the next available job from the specified queues using blocking list pop * Find the next available job from the specified queues using blocking list pop
* and return an instance of Resque_Job for it. * and return an instance of \Resque\Job\Job for it.
* *
* @param array $queues * @param array $queues
* @param int $timeout * @param int $timeout
* @return false|object Null when there aren't any waiting jobs, instance of Resque_Job when a job was found. *
* @return Job|null Null when there aren't any waiting jobs, instance of \Resque\Job\Job when a job was found.
*/ */
public static function reserveBlocking(array $queues, $timeout = null) public static function reserveBlocking(array $queues, $timeout = null): ?Job
{ {
$item = Resque::blpop($queues, $timeout); $item = \Resque\Resque::blpop($queues, $timeout);
if (!is_array($item)) { if (!is_array($item)) {
return false; return null;
} }
return new Resque_Job($item['queue'], $item['payload']); return new Job($item['queue'], $item['payload']);
} }
/** /**
* Update the status of the current job. * Update the status of the current job.
* *
* @param int $status Status constant from Resque_Job_Status indicating the current status of a job. * @param int $status Status constant from \Resque\Job\Status indicating the current status of a job.
*
* @return bool
*/ */
public function updateStatus($status): bool public function updateStatus($status): bool
{ {
@ -130,7 +137,7 @@ class Resque_Job
return false; return false;
} }
$statusInstance = new Resque_Job_Status($this->payload['id']); $statusInstance = new Status($this->payload['id']);
$statusInstance->update($status); $statusInstance->update($status);
return true; return true;
} }
@ -138,11 +145,11 @@ class Resque_Job
/** /**
* Return the status of the current job. * Return the status of the current job.
* *
* @return int The status of the job as one of the Resque_Job_Status constants. * @return int The status of the job as one of the \Resque\Job\Status constants.
*/ */
public function getStatus() public function getStatus()
{ {
$status = new Resque_Job_Status($this->payload['id']); $status = new Status($this->payload['id']);
return $status->get(); return $status->get();
} }
@ -162,11 +169,12 @@ class Resque_Job
/** /**
* Get the instantiated object for this job that will be performing work. * Get the instantiated object for this job that will be performing work.
* @return Resque_JobInterface Instance of the object that this job belongs to. *
* @return \Resque\Job\JobInterface Instance of the object that this job belongs to.
*/ */
public function getInstance() public function getInstance()
{ {
if (!is_null($this->instance)) { if (isset($this->instance) && !is_null($this->instance)) {
return $this->instance; return $this->instance;
} }
@ -180,12 +188,13 @@ class Resque_Job
* associated with the job with the supplied arguments. * associated with the job with the supplied arguments.
* *
* @return bool * @return bool
* @throws Resque_Exception When the job's class could not be found or it does not contain a perform method. *
* @throws \Resque\Exception When the job's class could not be found or it does not contain a perform method.
*/ */
public function perform() public function perform()
{ {
try { try {
Resque_Event::trigger('beforePerform', $this); \Resque\Event::trigger('beforePerform', $this);
$instance = $this->getInstance(); $instance = $this->getInstance();
if (method_exists($instance, 'setUp')) { if (method_exists($instance, 'setUp')) {
@ -198,9 +207,9 @@ class Resque_Job
$instance->tearDown(); $instance->tearDown();
} }
Resque_Event::trigger('afterPerform', $this); \Resque\Event::trigger('afterPerform', $this);
} // beforePerform/setUp have said don't perform this job. Return. } catch (DontPerform $e) {
/** @noinspection PhpRedundantCatchClauseInspection */ catch (Resque_Job_DontPerform $e) { /** @noinspection PhpRedundantCatchClauseInspection */
return false; return false;
} }
@ -214,29 +223,30 @@ class Resque_Job
*/ */
public function fail($exception) public function fail($exception)
{ {
Resque_Event::trigger('onFailure', [ \Resque\Event::trigger('onFailure', [
'exception' => $exception, 'exception' => $exception,
'job' => $this, 'job' => $this,
]); ]);
$this->updateStatus(Resque_Job_Status::STATUS_FAILED); $this->updateStatus(Status::STATUS_FAILED);
Resque_Failure::create( \Resque\Failure\Failure::create(
$this->payload, $this->payload,
$exception, $exception,
$this->worker, $this->worker,
$this->queue $this->queue
); );
Resque_Stat::incr('failed'); \Resque\Stat::incr('failed');
Resque_Stat::incr('failed:' . $this->worker); \Resque\Stat::incr('failed:' . $this->worker);
} }
/** /**
* Re-queue the current job. * Re-queue the current job.
*
* @return string * @return string
*/ */
public function recreate() public function recreate()
{ {
$status = new Resque_Job_Status($this->payload['id']); $status = new Status($this->payload['id']);
$monitor = false; $monitor = false;
if ($status->isTracking()) { if ($status->isTracking()) {
$monitor = true; $monitor = true;
@ -266,10 +276,11 @@ class Resque_Job
} }
/** /**
* @param Resque_Job_FactoryInterface $jobFactory * @param FactoryInterface $jobFactory
* @return Resque_Job *
* @return Job
*/ */
public function setJobFactory(Resque_Job_FactoryInterface $jobFactory) public function setJobFactory(FactoryInterface $jobFactory)
{ {
$this->jobFactory = $jobFactory; $this->jobFactory = $jobFactory;
@ -277,13 +288,14 @@ class Resque_Job
} }
/** /**
* @return Resque_Job_FactoryInterface * @return FactoryInterface
*/ */
public function getJobFactory() public function getJobFactory()
{ {
if ($this->jobFactory === null) { if (is_null($this->jobFactory)) {
$this->jobFactory = new Resque_Job_Factory(); $this->jobFactory = new Factory();
} }
return $this->jobFactory; return $this->jobFactory;
} }
} }

View file

@ -1,6 +1,8 @@
<?php <?php
interface Resque_JobInterface namespace Resque\Job;
interface JobInterface
{ {
/** /**
* @return bool * @return bool

View file

@ -1,19 +1,21 @@
<?php <?php
namespace Resque\Job;
/** /**
* Status tracker/information for a job. * Status tracker/information for a job.
* *
* @package Resque/Job * @package Resque/Job
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Job_Status class Status
{ {
const STATUS_WAITING = 1; public const STATUS_WAITING = 1;
const STATUS_RUNNING = 2; public const STATUS_RUNNING = 2;
const STATUS_FAILED = 3; public const STATUS_FAILED = 3;
const STATUS_COMPLETE = 4; public const STATUS_COMPLETE = 4;
/** /**
* @var string The ID of the job this status class refers back to. * @var string The ID of the job this status class refers back to.
@ -57,7 +59,11 @@ class Resque_Job_Status
'updated' => time(), 'updated' => time(),
'started' => time(), 'started' => time(),
]; ];
Resque::redis()->set('job:' . $id . ':status', json_encode($statusPacket)); \Resque\Resque::redis()->set(
'job:' . $id . ':status',
json_encode($statusPacket),
['ex' => \Resque\Redis::DEFAULT_REDIS_TTL],
);
} }
/** /**
@ -72,7 +78,7 @@ class Resque_Job_Status
return false; return false;
} }
if (!Resque::redis()->exists((string)$this)) { if (!\Resque\Resque::redis()->exists((string)$this)) {
$this->isTracking = false; $this->isTracking = false;
return false; return false;
} }
@ -84,7 +90,7 @@ class Resque_Job_Status
/** /**
* Update the status indicator for the current job with a new status. * Update the status indicator for the current job with a new status.
* *
* @param int The status of the job (see constants in Resque_Job_Status) * @param int The status of the job (see constants in \Resque\Job\Status)
*/ */
public function update($status) public function update($status)
{ {
@ -96,19 +102,19 @@ class Resque_Job_Status
'status' => $status, 'status' => $status,
'updated' => time(), 'updated' => time(),
]; ];
Resque::redis()->set((string)$this, json_encode($statusPacket));
// Expire the status for completed jobs after 24 hours \Resque\Resque::redis()->set(
if (in_array($status, self::$completeStatuses)) { (string)$this,
Resque::redis()->expire((string)$this, 86400); json_encode($statusPacket),
} ['ex' => \Resque\Redis::DEFAULT_REDIS_TTL],
);
} }
/** /**
* Fetch the status for the job being monitored. * Fetch the status for the job being monitored.
* *
* @return mixed False if the status is not being monitored, otherwise the status as * @return mixed False if the status is not being monitored, otherwise the status as
* as an integer, based on the Resque_Job_Status constants. * as an integer, based on the \Resque\Job\Status constants.
*/ */
public function get() public function get()
{ {
@ -116,7 +122,7 @@ class Resque_Job_Status
return false; return false;
} }
$statusPacket = json_decode(Resque::redis()->get((string)$this), true); $statusPacket = json_decode(\Resque\Resque::redis()->get((string)$this), true);
if (!$statusPacket) { if (!$statusPacket) {
return false; return false;
} }
@ -126,10 +132,12 @@ class Resque_Job_Status
/** /**
* Stop tracking the status of a job. * Stop tracking the status of a job.
*
* @return void
*/ */
public function stop() public function stop(): void
{ {
Resque::redis()->del((string)$this); \Resque\Resque::redis()->del((string)$this);
} }
/** /**

View file

@ -1,18 +1,20 @@
<?php <?php
namespace Resque;
/** /**
* Resque default logger PSR-3 compliant * Resque default logger PSR-3 compliant
* *
* @package Resque/Stat * @package Resque
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Log extends Psr\Log\AbstractLogger class Log extends \Psr\Log\AbstractLogger
{ {
public $logLevel; public $logLevel;
public function __construct($logLevel = "warning") public function __construct($logLevel = 'warning')
{ {
$this->logLevel = strtolower($logLevel); $this->logLevel = strtolower($logLevel);
} }
@ -23,21 +25,22 @@ class Resque_Log extends Psr\Log\AbstractLogger
* @param mixed $level PSR-3 log level constant, or equivalent string * @param mixed $level PSR-3 log level constant, or equivalent string
* @param string $message Message to log, may contain a { placeholder } * @param string $message Message to log, may contain a { placeholder }
* @param array $context Variables to replace { placeholder } * @param array $context Variables to replace { placeholder }
*
* @return null * @return null
*/ */
public function log($level, $message, array $context = []) public function log($level, $message, array $context = []): void
{ {
$logLevels = [ $logLevels = [
"emergency", 'emergency',
"alert", 'alert',
"critical", 'critical',
"error", 'error',
"warning", 'warning',
"notice", 'notice',
"info", 'info',
"debug" 'debug',
]; ];
/** /**
* Only log things with a higher level than the current log level. * Only log things with a higher level than the current log level.
* e.g If set as 'alert' will only alert for 'emergency' and 'alert' logs. * e.g If set as 'alert' will only alert for 'emergency' and 'alert' logs.
@ -45,7 +48,7 @@ class Resque_Log extends Psr\Log\AbstractLogger
if (array_search($level, $logLevels) <= array_search($this->logLevel, $logLevels)) { if (array_search($level, $logLevels) <= array_search($this->logLevel, $logLevels)) {
fwrite( fwrite(
STDOUT, STDOUT,
'[' . $level . '][' . strftime('%Y-%m-%d %T') . '] ' . '[' . $level . '][' . date('Y-m-d H:i:s') . '] ' .
$this->interpolate($message, $context) . PHP_EOL $this->interpolate($message, $context) . PHP_EOL
); );
} }

View file

@ -1,23 +1,27 @@
<?php <?php
namespace Resque;
/** /**
* Set up phpredis connection * Set up phpredis connection
* *
* @package Resque/Redis * @package Resque/Redis
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Redis class Redis
{ {
/** /**
* Redis Client * Redis Client
* @var Credis_Client *
* @var \Credis_Client
*/ */
private $driver; private $driver;
/** /**
* Redis namespace * Redis namespace
*
* @var string * @var string
*/ */
private static $defaultNamespace = 'resque:'; private static $defaultNamespace = 'resque:';
@ -25,17 +29,22 @@ class Resque_Redis
/** /**
* A default host to connect to * A default host to connect to
*/ */
const DEFAULT_HOST = 'localhost'; public const DEFAULT_HOST = 'localhost';
/** /**
* The default Redis port * The default Redis port
*/ */
const DEFAULT_PORT = 6379; public const DEFAULT_PORT = 6379;
/** /**
* The default Redis Database number * The default Redis Database number
*/ */
const DEFAULT_DATABASE = 0; public const DEFAULT_DATABASE = 0;
/**
* Default Redis TTL (2 days)
*/
public const DEFAULT_REDIS_TTL = 172800;
/** /**
* @var array List of all commands in Redis that supply a key as their * @var array List of all commands in Redis that supply a key as their
@ -88,27 +97,20 @@ class Resque_Redis
'rename', 'rename',
'rpoplpush' 'rpoplpush'
]; ];
// sinterstore
// sunion
// sunionstore
// sdiff
// sdiffstore
// sinter
// smove
// mget
// msetnx
// mset
// renamenx
/** /**
* Set Redis namespace (prefix) default: resque * Set Redis namespace (prefix) default: resque
*
* @param string $namespace * @param string $namespace
*
* @return void
*/ */
public static function prefix($namespace) public static function prefix(string $namespace): void
{ {
if (substr($namespace, -1) !== ':' && $namespace != '') { if (substr($namespace, -1) !== ':' && $namespace != '') {
$namespace .= ':'; $namespace .= ':';
} }
self::$defaultNamespace = $namespace; self::$defaultNamespace = $namespace;
} }
@ -116,8 +118,9 @@ class Resque_Redis
* @param string|array $server A DSN or array * @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 * @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. * DSN-supplied value will be used instead and this parameter is ignored.
* @param object $client Optional Credis_Client instance instantiated by you * @param object $client Optional \Credis_Client instance instantiated by you
* @throws Resque_RedisException *
* @throws \Resque\RedisException
*/ */
public function __construct($server, $database = null, $client = null) public function __construct($server, $database = null, $client = null)
{ {
@ -131,7 +134,7 @@ class Resque_Redis
$timeout = isset($options['timeout']) ? intval($options['timeout']) : null; $timeout = isset($options['timeout']) ? intval($options['timeout']) : null;
$persistent = isset($options['persistent']) ? $options['persistent'] : ''; $persistent = isset($options['persistent']) ? $options['persistent'] : '';
$maxRetries = isset($options['max_connect_retries']) ? $options['max_connect_retries'] : 0; $maxRetries = isset($options['max_connect_retries']) ? $options['max_connect_retries'] : 0;
$this->driver = new Credis_Client($host, $port, $timeout, $persistent); $this->driver = new \Credis_Client($host, $port, $timeout, $persistent);
$this->driver->setMaxConnectRetries($maxRetries); $this->driver->setMaxConnectRetries($maxRetries);
if ($password) { if ($password) {
$this->driver->auth($password); $this->driver->auth($password);
@ -145,8 +148,8 @@ class Resque_Redis
if ($database !== null) { if ($database !== null) {
$this->driver->select($database); $this->driver->select($database);
} }
} catch (Exception $e) { } catch (\Exception $e) {
throw new Resque_RedisException('Error communicating with Redis: ' . $e->getMessage(), 0, $e); throw new RedisException('Error communicating with Redis: ' . $e->getMessage(), 0, $e);
} }
} }
@ -161,10 +164,11 @@ class Resque_Redis
* Note: the 'user' part of the DSN is not used. * Note: the 'user' part of the DSN is not used.
* *
* @param string $dsn A DSN string * @param string $dsn A DSN string
*
* @return array An array of DSN compotnents, with 'false' values for any unknown components. e.g. * @return array An array of DSN compotnents, with 'false' values for any unknown components. e.g.
* [host, port, db, user, pass, options] * [host, port, db, user, pass, options]
*/ */
public static function parseDsn($dsn) public static function parseDsn($dsn): array
{ {
if ($dsn == '') { if ($dsn == '') {
// Use a sensible default for an empty DNS string // Use a sensible default for an empty DNS string
@ -185,7 +189,7 @@ class Resque_Redis
// Check the URI scheme // Check the URI scheme
$validSchemes = ['redis', 'tcp']; $validSchemes = ['redis', 'tcp'];
if (isset($parts['scheme']) && !in_array($parts['scheme'], $validSchemes)) { if (isset($parts['scheme']) && !in_array($parts['scheme'], $validSchemes)) {
throw new InvalidArgumentException("Invalid DSN. Supported schemes are " . implode(', ', $validSchemes)); throw new \InvalidArgumentException("Invalid DSN. Supported schemes are " . implode(', ', $validSchemes));
} }
// Allow simple 'hostname' format, which `parse_url` treats as a path, not host. // Allow simple 'hostname' format, which `parse_url` treats as a path, not host.
@ -231,14 +235,16 @@ class Resque_Redis
* *
* @param string $name The name of the method called. * @param string $name The name of the method called.
* @param array $args Array of supplied arguments to the method. * @param array $args Array of supplied arguments to the method.
*
* @return mixed Return value from Resident::call() based on the command. * @return mixed Return value from Resident::call() based on the command.
*
* @throws Resque_RedisException * @throws Resque_RedisException
*/ */
public function __call($name, $args) public function __call($name, $args)
{ {
if (in_array($name, $this->keyCommands)) { if (in_array($name, $this->keyCommands)) {
if (is_array($args[0])) { if (is_array($args[0])) {
foreach ($args[0] AS $i => $v) { foreach ($args[0] as $i => $v) {
$args[0][$i] = self::$defaultNamespace . $v; $args[0][$i] = self::$defaultNamespace . $v;
} }
} else { } else {
@ -247,23 +253,18 @@ class Resque_Redis
} }
try { try {
return $this->driver->__call($name, $args); return $this->driver->__call($name, $args);
} catch (CredisException $e) { } catch (\Exception $e) {
throw new Resque_RedisException('Error communicating with Redis: ' . $e->getMessage(), 0, $e); throw new RedisException('Error communicating with Redis: ' . $e->getMessage(), 0, $e);
} }
} }
/**
* Returns redis prefix
*
* @return string
*/
public static function getPrefix(): string public static function getPrefix(): string
{ {
return self::$defaultNamespace; return self::$defaultNamespace;
} }
public static function removePrefix($string): string
{
$prefix = self::getPrefix();
if (substr($string, 0, strlen($prefix)) == $prefix) {
$string = substr($string, strlen($prefix), strlen($string));
}
return $string;
}
} }

View file

@ -0,0 +1,15 @@
<?php
namespace Resque;
/**
* Redis exceptions
*
* @package Resque
* @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php
*/
class RedisException extends \Exception
{
}

View file

@ -1,18 +1,20 @@
<?php <?php
namespace Resque;
/** /**
* Base Resque class. * Base Resque class.
* *
* @package Resque * @package Resque
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque class Resque
{ {
const VERSION = '1.4.5'; public const VERSION = '2.5.3';
const DEFAULT_INTERVAL = 5; public const DEFAULT_INTERVAL = 5;
/** /**
* @var Resque_Redis Instance of Resque_Redis that talks to redis. * @var Resque_Redis Instance of Resque_Redis that talks to redis.
@ -50,19 +52,20 @@ class Resque
/** /**
* Return an instance of the Resque_Redis class instantiated for Resque. * Return an instance of the Resque_Redis class instantiated for Resque.
* *
* @return Resque_Redis Instance of Resque_Redis. * @return \Resque\Redis Instance of Resque_Redis.
* @throws Resque_RedisException *
* @throws \Resque\RedisException
*/ */
public static function redis() public static function redis()
{ {
if (self::$redis !== null) { if (!is_null(self::$redis)) {
return self::$redis; return self::$redis;
} }
if (is_callable(self::$redisServer)) { if (is_callable(self::$redisServer)) {
self::$redis = call_user_func(self::$redisServer, self::$redisDatabase); self::$redis = call_user_func(self::$redisServer, self::$redisDatabase);
} else { } else {
self::$redis = new Resque_Redis(self::$redisServer, self::$redisDatabase); self::$redis = new \Resque\Redis(self::$redisServer, self::$redisDatabase);
} }
return self::$redis; return self::$redis;
@ -89,7 +92,7 @@ class Resque
$pid = pcntl_fork(); $pid = pcntl_fork();
if ($pid === -1) { if ($pid === -1) {
throw new RuntimeException('Unable to fork child worker.'); throw new \RuntimeException('Unable to fork child worker.');
} }
return $pid; return $pid;
@ -101,19 +104,23 @@ class Resque
* *
* @param string $queue The name of the queue to add the job to. * @param string $queue The name of the queue to add the job to.
* @param array $item Job description as an array to be JSON encoded. * @param array $item Job description as an array to be JSON encoded.
*
* @return bool * @return bool
*/ */
public static function push($queue, $item) public static function push($queue, $item): bool
{ {
$encodedItem = json_encode($item); $encodedItem = json_encode($item);
if ($encodedItem === false) { if ($encodedItem === false) {
return false; return false;
} }
self::redis()->sadd('queues', $queue); self::redis()->sadd('queues', $queue);
$length = self::redis()->rpush('queue:' . $queue, $encodedItem); $length = self::redis()->rpush('queue:' . $queue, $encodedItem);
if ($length < 1) { if ($length < 1) {
return false; return false;
} }
return true; return true;
} }
@ -122,6 +129,7 @@ class Resque
* return it. * return it.
* *
* @param string $queue The name of the queue to fetch an item from. * @param string $queue The name of the queue to fetch an item from.
*
* @return mixed Decoded item from the queue. * @return mixed Decoded item from the queue.
*/ */
public static function pop($queue) public static function pop($queue)
@ -142,7 +150,7 @@ class Resque
* @param array $items * @param array $items
* @return integer number of deleted items * @return integer number of deleted items
*/ */
public static function dequeue($queue, $items = Array()) public static function dequeue($queue, $items = [])
{ {
if (count($items) > 0) { if (count($items) > 0) {
return self::removeItems($queue, $items); return self::removeItems($queue, $items);
@ -155,13 +163,14 @@ class Resque
* Remove specified queue * Remove specified queue
* *
* @param string $queue The name of the queue to remove. * @param string $queue The name of the queue to remove.
* @return integer Number of deleted items *
* @return int Number of deleted items
*/ */
public static function removeQueue($queue) public static function removeQueue($queue): int
{ {
$num = self::removeList($queue); $num = self::removeList($queue);
self::redis()->srem('queues', $queue); self::redis()->srem('queues', $queue);
return $num; return intval($num);
} }
/** /**
@ -170,12 +179,13 @@ class Resque
* *
* @param array $queues * @param array $queues
* @param int $timeout * @param int $timeout
*
* @return array|null|void * @return array|null|void
*/ */
public static function blpop(array $queues, $timeout) public static function blpop(array $queues, $timeout)
{ {
$list = array(); $list = [];
foreach ($queues AS $queue) { foreach ($queues as $queue) {
$list[] = 'queue:' . $queue; $list[] = 'queue:' . $queue;
} }
@ -192,10 +202,10 @@ class Resque
*/ */
$queue = substr($item[0], strlen(self::redis()->getPrefix() . 'queue:')); $queue = substr($item[0], strlen(self::redis()->getPrefix() . 'queue:'));
return array( return [
'queue' => $queue, 'queue' => $queue,
'payload' => json_decode($item[1], true) 'payload' => json_decode($item[1], true)
); ];
} }
/** /**
@ -205,9 +215,9 @@ class Resque
* *
* @return int The size of the queue. * @return int The size of the queue.
*/ */
public static function size($queue) public static function size($queue): int
{ {
return self::redis()->llen('queue:' . $queue); return intval(self::redis()->llen('queue:' . $queue));
} }
/** /**
@ -223,20 +233,20 @@ class Resque
public static function enqueue($queue, $class, $args = null, $trackStatus = false) public static function enqueue($queue, $class, $args = null, $trackStatus = false)
{ {
$id = Resque::generateJobId(); $id = Resque::generateJobId();
$hookParams = array( $hookParams = [
'class' => $class, 'class' => $class,
'args' => $args, 'args' => $args,
'queue' => $queue, 'queue' => $queue,
'id' => $id, 'id' => $id,
); ];
try { try {
Resque_Event::trigger('beforeEnqueue', $hookParams); \Resque\Event::trigger('beforeEnqueue', $hookParams);
} catch (Resque_Job_DontCreate $e) { } catch (\Resque\Job\DontCreate $e) {
return false; return false;
} }
Resque_Job::create($queue, $class, $args, $trackStatus, $id); \Resque\Job\Job::create($queue, $class, $args, $trackStatus, $id);
Resque_Event::trigger('afterEnqueue', $hookParams); \Resque\Event::trigger('afterEnqueue', $hookParams);
return $id; return $id;
} }
@ -245,11 +255,12 @@ class Resque
* Reserve and return the next available job in the specified queue. * Reserve and return the next available job in the specified queue.
* *
* @param string $queue Queue to fetch next available job from. * @param string $queue Queue to fetch next available job from.
* @return false|object|Resque_Job *
* @return \Resque\Job\Job|null
*/ */
public static function reserve($queue) public static function reserve($queue): ?\Resque\Job\Job
{ {
return Resque_Job::reserve($queue); return \Resque\Job\Job::reserve($queue);
} }
/** /**
@ -257,13 +268,10 @@ class Resque
* *
* @return array Array of queues. * @return array Array of queues.
*/ */
public static function queues() public static function queues(): array
{ {
$queues = self::redis()->smembers('queues'); $queues = self::redis()->smembers('queues');
if (!is_array($queues)) { return is_array($queues) ? $queues : [];
$queues = array();
}
return $queues;
} }
/** /**
@ -276,9 +284,10 @@ class Resque
* *
* @param string $queue The name of the queue * @param string $queue The name of the queue
* @param array $items * @param array $items
* @return integer number of deleted items *
* @return int number of deleted items
*/ */
private static function removeItems($queue, $items = Array()) private static function removeItems($queue, $items = []): int
{ {
$counter = 0; $counter = 0;
$originalQueue = 'queue:' . $queue; $originalQueue = 'queue:' . $queue;
@ -343,8 +352,11 @@ class Resque
# class name with args , example: item[0] = ['class' => {'foo' => 1, 'bar' => 2}] # class name with args , example: item[0] = ['class' => {'foo' => 1, 'bar' => 2}]
} elseif (is_array($val)) { } elseif (is_array($val)) {
$decodedArgs = (array)$decoded['args'][0]; $decodedArgs = (array)$decoded['args'][0];
if ($decoded['class'] == $key && if (
count($decodedArgs) > 0 && count(array_diff($decodedArgs, $val)) == 0) { $decoded['class'] == $key
&& count($decodedArgs) > 0
&& count(array_diff($decodedArgs, $val)) == 0
) {
return true; return true;
} }
# class name with ID, example: item[0] = ['class' => 'id'] # class name with ID, example: item[0] = ['class' => 'id']
@ -365,7 +377,7 @@ class Resque
* @params string $queue the name of the queue * @params string $queue the name of the queue
* @param $queue * @param $queue
* @return integer number of deleted items belongs to this list * @return integer number of deleted items belongs to this list
* @throws Resque_RedisException * @throws \Resque\RedisException
*/ */
private static function removeList($queue) private static function removeList($queue)
{ {

View file

@ -1,22 +1,25 @@
<?php <?php
namespace Resque;
/** /**
* Resque statistic management (jobs processed, failed, etc) * Resque statistic management (jobs processed, failed, etc)
* *
* @package Resque/Stat * @package Resque
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Stat class Stat
{ {
/** /**
* Get the value of the supplied statistic counter for the specified statistic. * Get the value of the supplied statistic counter for the specified statistic.
* *
* @param string $stat The name of the statistic to get the stats for. * @param string $stat The name of the statistic to get the stats for.
* @return mixed Value of the statistic. *
* @return int Value of the statistic.
*/ */
public static function get($stat): int public static function get(string $stat): int
{ {
return (int)Resque::redis()->get('stat:' . $stat); return (int)Resque::redis()->get('stat:' . $stat);
} }
@ -26,11 +29,24 @@ class Resque_Stat
* *
* @param string $stat The name of the statistic to increment. * @param string $stat The name of the statistic to increment.
* @param int $by The amount to increment the statistic by. * @param int $by The amount to increment the statistic by.
* @return boolean True if successful, false if not. *
* @return bool True if successful, false if not.
*/ */
public static function incr($stat, $by = 1): bool public static function incr(string $stat, int $by = 1): bool
{ {
return (bool)Resque::redis()->incrby('stat:' . $stat, $by); // Make sure we set a TTL by default
$set = Resque::redis()->set(
'stat:' . $stat,
$by,
['ex' => Redis::DEFAULT_REDIS_TTL, 'nx'],
);
// If it already exists, return the incrby value
if (!$set) {
return (bool)Resque::redis()->incrby('stat:' . $stat, $by);
}
return true;
} }
/** /**
@ -38,9 +54,10 @@ class Resque_Stat
* *
* @param string $stat The name of the statistic to decrement. * @param string $stat The name of the statistic to decrement.
* @param int $by The amount to decrement the statistic by. * @param int $by The amount to decrement the statistic by.
* @return boolean True if successful, false if not. *
* @return bool True if successful, false if not.
*/ */
public static function decr($stat, $by = 1): bool public static function decr(string $stat, int $by = 1): bool
{ {
return (bool)Resque::redis()->decrby('stat:' . $stat, $by); return (bool)Resque::redis()->decrby('stat:' . $stat, $by);
} }
@ -49,10 +66,11 @@ class Resque_Stat
* Delete a statistic with the given name. * Delete a statistic with the given name.
* *
* @param string $stat The name of the statistic to delete. * @param string $stat The name of the statistic to delete.
* @return boolean True if successful, false if not. *
* @return bool True if successful, false if not.
*/ */
public static function clear($stat): bool public static function clear(string $stat): bool
{ {
return (bool)Resque::redis()->del('stat:' . $stat); return (bool)Resque::redis()->del('stat:' . $stat);
} }
} }

View file

@ -1,17 +1,20 @@
<?php <?php
declare(ticks=1); declare(ticks=1);
namespace Resque;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
/** /**
* Resque worker that handles checking queues for jobs, fetching them * Resque worker that handles checking queues for jobs, fetching them
* off the queues, running them and handling the result. * off the queues, running them and handling the result.
* *
* @package Resque/Worker * @package Resque
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Worker class Worker
{ {
/** /**
* @var LoggerInterface Logging object that impliments the PSR-3 LoggerInterface * @var LoggerInterface Logging object that impliments the PSR-3 LoggerInterface
@ -44,7 +47,7 @@ class Resque_Worker
private $id; private $id;
/** /**
* @var Resque_Job Current job, if any, being processed by this worker. * @var \Resque\Job\Job Current job, if any, being processed by this worker.
*/ */
private $currentJob = null; private $currentJob = null;
@ -66,7 +69,7 @@ class Resque_Worker
*/ */
public function __construct($queues) public function __construct($queues)
{ {
$this->logger = new Resque_Log(); $this->logger = new Log();
if (!is_array($queues)) { if (!is_array($queues)) {
$queues = [$queues]; $queues = [$queues];
@ -80,6 +83,7 @@ class Resque_Worker
/** /**
* Return all workers known to Resque as instantiated instances. * Return all workers known to Resque as instantiated instances.
*
* @return array * @return array
*/ */
public static function all(): array public static function all(): array
@ -93,14 +97,17 @@ class Resque_Worker
foreach ($workers as $workerId) { foreach ($workers as $workerId) {
$instances[] = self::find($workerId); $instances[] = self::find($workerId);
} }
return $instances; return $instances;
} }
/** /**
* Given a worker ID, check if it is registered/valid. * Given a worker ID, check if it is registered/valid.
* *
* @param string $workerId ID of the worker. * @param string $workerId ID of the worker
* @return boolean True if the worker exists, false if not. *
* @return boolean True if the worker exists, false if not
*
* @throws Resque_RedisException * @throws Resque_RedisException
*/ */
public static function exists($workerId): bool public static function exists($workerId): bool
@ -111,20 +118,24 @@ class Resque_Worker
/** /**
* Given a worker ID, find it and return an instantiated worker class for it. * Given a worker ID, find it and return an instantiated worker class for it.
* *
* @param string $workerId The ID of the worker. * @param string $workerId The ID of the worker
* @return bool|Resque_Worker *
* @return Resque_Worker|bool
*
* @throws Resque_RedisException * @throws Resque_RedisException
*/ */
public static function find($workerId) public static function find($workerId)
{ {
if (!self::exists($workerId) || false === strpos($workerId, ":")) { if (false === strpos($workerId, ":") || !self::exists($workerId)) {
return false; return false;
} }
/** @noinspection PhpUnusedLocalVariableInspection */ /** @noinspection PhpUnusedLocalVariableInspection */
list($hostname, $pid, $queues) = explode(':', $workerId, 3); list($hostname, $pid, $queues) = explode(':', $workerId, 3);
$queues = explode(',', $queues); $queues = explode(',', $queues);
$worker = new self($queues); $worker = new self($queues);
$worker->setId($workerId); $worker->setId($workerId);
return $worker; return $worker;
} }
@ -132,8 +143,10 @@ class Resque_Worker
* Set the ID of this worker to a given ID string. * Set the ID of this worker to a given ID string.
* *
* @param string $workerId ID for the worker. * @param string $workerId ID for the worker.
*
* @return void
*/ */
public function setId($workerId) public function setId($workerId): void
{ {
$this->id = $workerId; $this->id = $workerId;
} }
@ -146,9 +159,12 @@ class Resque_Worker
* *
* @param int $interval How often to check for new jobs across the queues. * @param int $interval How often to check for new jobs across the queues.
* @param bool $blocking * @param bool $blocking
*
* @return void
*
* @throws Resque_RedisException * @throws Resque_RedisException
*/ */
public function work($interval = Resque::DEFAULT_INTERVAL, $blocking = false) public function work($interval = Resque::DEFAULT_INTERVAL, $blocking = false): void
{ {
$this->updateProcLine('Starting'); $this->updateProcLine('Starting');
$this->startup(); $this->startup();
@ -162,8 +178,14 @@ class Resque_Worker
$job = false; $job = false;
if (!$this->paused) { if (!$this->paused) {
if ($blocking === true) { if ($blocking === true) {
$this->logger->log(Psr\Log\LogLevel::INFO, 'Starting blocking with timeout of {interval}', ['interval' => $interval]); $this->logger->log(
$this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with blocking timeout ' . $interval); \Psr\Log\LogLevel::INFO,
'Starting blocking with timeout of {interval}',
['interval' => $interval],
);
$this->updateProcLine(
'Waiting for ' . implode(',', $this->queues) . ' with blocking timeout ' . $interval
);
} else { } else {
$this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval);
} }
@ -179,7 +201,12 @@ class Resque_Worker
if ($blocking === false) { if ($blocking === false) {
// If no job was found, we sleep for $interval before continuing and checking again // If no job was found, we sleep for $interval before continuing and checking again
$this->logger->log(Psr\Log\LogLevel::INFO, 'Sleeping for {interval}', ['interval' => $interval]); $this->logger->log(
\Psr\Log\LogLevel::INFO,
'Sleeping for {interval}',
['interval' => $interval],
);
if ($this->paused) { if ($this->paused) {
$this->updateProcLine('Paused'); $this->updateProcLine('Paused');
} else { } else {
@ -192,17 +219,19 @@ class Resque_Worker
continue; continue;
} }
$this->logger->log(Psr\Log\LogLevel::NOTICE, 'Starting work on {job}', ['job' => $job]); $this->logger->log(\Psr\Log\LogLevel::NOTICE, 'Starting work on {job}', ['job' => $job]);
Resque_Event::trigger('beforeFork', $job); Event::trigger('beforeFork', $job);
$this->workingOn($job); $this->workingOn($job);
$this->child = Resque::fork(); $this->child = Resque::fork();
// Forked and we're the child. Run the job. // 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'); $status = 'Processing ' . $job->queue
. ' (' . ($job->payload['class'] ?? '') . ') since '
. date('Y-m-d H:i:s');
$this->updateProcLine($status); $this->updateProcLine($status);
$this->logger->log(Psr\Log\LogLevel::INFO, $status); $this->logger->log(\Psr\Log\LogLevel::INFO, $status);
/** @noinspection PhpParamsInspection */ /** @noinspection PhpParamsInspection */
$this->perform($job); $this->perform($job);
if ($this->child === 0) { if ($this->child === 0) {
@ -212,15 +241,15 @@ class Resque_Worker
if ($this->child > 0) { if ($this->child > 0) {
// Parent process, sit and wait // Parent process, sit and wait
$status = 'Forked ' . $this->child . ' at ' . strftime('%F %T'); $status = 'Forked ' . $this->child . ' at ' . date('Y-m-d H:i:s');
$this->updateProcLine($status); $this->updateProcLine($status);
$this->logger->log(Psr\Log\LogLevel::INFO, $status); $this->logger->log(\Psr\Log\LogLevel::INFO, $status);
// Wait until the child process finishes before continuing // Wait until the child process finishes before continuing
pcntl_wait($status); pcntl_wait($status);
$exitStatus = pcntl_wexitstatus($status); $exitStatus = pcntl_wexitstatus($status);
if ($exitStatus !== 0) { if ($exitStatus !== 0) {
$job->fail(new Resque_Job_DirtyExitException( $job->fail(new \Resque\Job\DirtyExitException(
'Job exited with exit code ' . $exitStatus 'Job exited with exit code ' . $exitStatus
)); ));
} }
@ -234,29 +263,32 @@ class Resque_Worker
} }
/** /**
* Process a single job. * Process a single job
* *
* @param Resque_Job $job The job to be processed. * @param \Resque\Job\Job $job The job to be processed
*
* @return void
*/ */
public function perform(Resque_Job $job) public function perform(\Resque\Job\Job $job): void
{ {
try { try {
Resque_Event::trigger('afterFork', $job); Event::trigger('afterFork', $job);
$job->perform(); $job->perform();
} catch (Exception $e) { } catch (\Exception $e) {
$this->logger->log(Psr\Log\LogLevel::CRITICAL, '{job} has failed {stack}', ['job' => $job, 'stack' => $e]); $this->logger->log(\Psr\Log\LogLevel::CRITICAL, '{job} has failed {stack}', ['job' => $job, 'stack' => $e]);
$job->fail($e); $job->fail($e);
return; return;
} }
$job->updateStatus(Resque_Job_Status::STATUS_COMPLETE); $job->updateStatus(\Resque\Job\Status::STATUS_COMPLETE);
$this->logger->log(Psr\Log\LogLevel::NOTICE, '{job} has finished', ['job' => $job]); $this->logger->log(\Psr\Log\LogLevel::NOTICE, '{job} has finished', ['job' => $job]);
} }
/** /**
* @param bool $blocking * @param bool $blocking
* @param int $timeout * @param int $timeout
* @return object|boolean Instance of Resque_Job if a job is found, false if not. *
* @return object|boolean - Instance of \Resque\Job\Job if a job is found, false if not
*/ */
public function reserve($blocking = false, $timeout = null) public function reserve($blocking = false, $timeout = null)
{ {
@ -266,17 +298,17 @@ class Resque_Worker
} }
if ($blocking === true) { if ($blocking === true) {
$job = Resque_Job::reserveBlocking($queues, $timeout); $job = \Resque\Job\Job::reserveBlocking($queues, $timeout);
if ($job) { if (!is_null($job)) {
$this->logger->log(Psr\Log\LogLevel::INFO, 'Found job on {queue}', ['queue' => $job->queue]); $this->logger->log(\Psr\Log\LogLevel::INFO, 'Found job on {queue}', ['queue' => $job->queue]);
return $job; return $job;
} }
} else { } else {
foreach ($queues as $queue) { foreach ($queues as $queue) {
$this->logger->log(Psr\Log\LogLevel::INFO, 'Checking {queue} for jobs', ['queue' => $queue]); $this->logger->log(\Psr\Log\LogLevel::INFO, 'Checking {queue} for jobs', ['queue' => $queue]);
$job = Resque_Job::reserve($queue); $job = \Resque\Job\Job::reserve($queue);
if ($job) { if (!is_null($job)) {
$this->logger->log(Psr\Log\LogLevel::INFO, 'Found job on {queue}', ['queue' => $job->queue]); $this->logger->log(\Psr\Log\LogLevel::INFO, 'Found job on {queue}', ['queue' => $job->queue]);
return $job; return $job;
} }
} }
@ -287,16 +319,17 @@ class Resque_Worker
/** /**
* Return an array containing all of the queues that this worker should use * Return an array containing all of the queues that this worker should use
* when searching for jobs. * when searching for jobs
* *
* If * is found in the list of queues, every queue will be searched in * If * is found in the list of queues, every queue will be searched in
* alphabetic order. (@param boolean $fetch If true, and the queue is set to *, will fetch * alphabetic order. (@param boolean $fetch If true, and the queue is set to *, will fetch
* all queue names from redis. * all queue names from redis
* @return array Array of associated queues.
* @see $fetch)
* *
* @param boolean $fetch
*
* @return array Array of associated queues
*/ */
public function queues($fetch = true) public function queues(bool $fetch = true): array
{ {
if (!in_array('*', $this->queues) || $fetch == false) { if (!in_array('*', $this->queues) || $fetch == false) {
return $this->queues; return $this->queues;
@ -304,17 +337,20 @@ class Resque_Worker
$queues = Resque::queues(); $queues = Resque::queues();
sort($queues); sort($queues);
return $queues; return $queues;
} }
/** /**
* Perform necessary actions to start a worker. * Perform necessary actions to start a worker
*
* @return void
*/ */
private function startup() private function startup(): void
{ {
$this->registerSigHandlers(); $this->registerSigHandlers();
$this->pruneDeadWorkers(); $this->pruneDeadWorkers();
Resque_Event::trigger('beforeFirstFork', $this); Event::trigger('beforeFirstFork', $this);
$this->registerWorker(); $this->registerWorker();
} }
@ -323,14 +359,16 @@ class Resque_Worker
* the name of the currently running process to indicate the current state * the name of the currently running process to indicate the current state
* of a worker. * of a worker.
* *
* @param string $status The updated process title. * @param string $status The updated process title
*
* @return void
*/ */
private function updateProcLine($status) private function updateProcLine($status): void
{ {
$processTitle = 'resque-' . Resque::VERSION . ': ' . $status; $processTitle = 'resque-' . Resque::VERSION . ': ' . $status;
if (function_exists('cli_set_process_title') && PHP_OS !== 'Darwin') { if (function_exists('cli_set_process_title') && PHP_OS !== 'Darwin') {
cli_set_process_title($processTitle); cli_set_process_title($processTitle);
} else if (function_exists('setproctitle')) { } elseif (function_exists('setproctitle')) {
setproctitle($processTitle); setproctitle($processTitle);
} }
} }
@ -342,8 +380,10 @@ class Resque_Worker
* INT: Shutdown immediately and stop processing jobs. * INT: Shutdown immediately and stop processing jobs.
* QUIT: Shutdown after the current job finishes processing. * QUIT: Shutdown after the current job finishes processing.
* USR1: Kill the forked child immediately and continue processing jobs. * USR1: Kill the forked child immediately and continue processing jobs.
*
* @return void
*/ */
private function registerSigHandlers() private function registerSigHandlers(): void
{ {
if (!function_exists('pcntl_signal')) { if (!function_exists('pcntl_signal')) {
return; return;
@ -355,43 +395,51 @@ class Resque_Worker
pcntl_signal(SIGUSR1, [$this, 'killChild']); pcntl_signal(SIGUSR1, [$this, 'killChild']);
pcntl_signal(SIGUSR2, [$this, 'pauseProcessing']); pcntl_signal(SIGUSR2, [$this, 'pauseProcessing']);
pcntl_signal(SIGCONT, [$this, 'unPauseProcessing']); pcntl_signal(SIGCONT, [$this, 'unPauseProcessing']);
$this->logger->log(Psr\Log\LogLevel::DEBUG, 'Registered signals'); $this->logger->log(\Psr\Log\LogLevel::DEBUG, 'Registered signals');
} }
/** /**
* Signal handler callback for USR2, pauses processing of new jobs. * Signal handler callback for USR2, pauses processing of new jobs
*
* @return void
*/ */
public function pauseProcessing() public function pauseProcessing(): void
{ {
$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; $this->paused = true;
} }
/** /**
* Signal handler callback for CONT, resumes worker allowing it to pick * Signal handler callback for CONT, resumes worker allowing it to pick
* up new jobs. * up new jobs.
*
* @return void
*/ */
public function unPauseProcessing() public function unPauseProcessing(): void
{ {
$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; $this->paused = false;
} }
/** /**
* Schedule a worker for shutdown. Will finish processing the current job * Schedule a worker for shutdown. Will finish processing the current job
* and when the timeout interval is reached, the worker will shut down. * and when the timeout interval is reached, the worker will shut down.
*
* @return void
*/ */
public function shutdown() public function shutdown(): void
{ {
$this->shutdown = true; $this->shutdown = true;
$this->logger->log(Psr\Log\LogLevel::NOTICE, 'Shutting down'); $this->logger->log(\Psr\Log\LogLevel::NOTICE, 'Shutting down');
} }
/** /**
* Force an immediate shutdown of the worker, killing any child jobs * Force an immediate shutdown of the worker, killing any child jobs
* currently running. * currently running.
*
* @return void
*/ */
public function shutdownNow() public function shutdownNow(): void
{ {
$this->shutdown(); $this->shutdown();
$this->killChild(); $this->killChild();
@ -400,21 +448,27 @@ class Resque_Worker
/** /**
* Kill a forked child job immediately. The job it is processing will not * Kill a forked child job immediately. The job it is processing will not
* be completed. * be completed.
*
* @return void
*/ */
public function killChild() public function killChild(): void
{ {
if (!$this->child) { 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; return;
} }
$this->logger->log(Psr\Log\LogLevel::INFO, 'Killing child at {child}', ['child' => $this->child]); $this->logger->log(\Psr\Log\LogLevel::INFO, 'Killing child at {child}', ['child' => $this->child]);
if (exec('ps -o pid,state -p ' . $this->child, $output, $returnCode) && $returnCode != 1) { if (exec('ps -o pid,state -p ' . $this->child, $output, $returnCode) && $returnCode != 1) {
$this->logger->log(Psr\Log\LogLevel::DEBUG, 'Child {child} found, killing.', ['child' => $this->child]); $this->logger->log(\Psr\Log\LogLevel::DEBUG, 'Child {child} found, killing.', ['child' => $this->child]);
posix_kill($this->child, SIGKILL); posix_kill($this->child, SIGKILL);
$this->child = null; $this->child = null;
} else { } else {
$this->logger->log(Psr\Log\LogLevel::INFO, 'Child {child} not found, restarting.', ['child' => $this->child]); $this->logger->log(
\Psr\Log\LogLevel::INFO,
'Child {child} not found, restarting.',
['child' => $this->child],
);
$this->shutdown(); $this->shutdown();
} }
} }
@ -426,8 +480,10 @@ class Resque_Worker
* This is a form of garbage collection to handle cases where the * This is a form of garbage collection to handle cases where the
* server may have been killed and the Resque workers did not die gracefully * server may have been killed and the Resque workers did not die gracefully
* and therefore leave state information in Redis. * and therefore leave state information in Redis.
*
* @return void
*/ */
public function pruneDeadWorkers() public function pruneDeadWorkers(): void
{ {
$workerPids = $this->workerPids(); $workerPids = $this->workerPids();
$workers = self::all(); $workers = self::all();
@ -437,7 +493,11 @@ class Resque_Worker
if ($host != $this->hostname || in_array($pid, $workerPids) || $pid == getmypid()) { if ($host != $this->hostname || in_array($pid, $workerPids) || $pid == getmypid()) {
continue; continue;
} }
$this->logger->log(Psr\Log\LogLevel::INFO, 'Pruning dead worker: {worker}', ['worker' => (string)$worker]); $this->logger->log(
\Psr\Log\LogLevel::INFO,
'Pruning dead worker: {worker}',
['worker' => (string)$worker],
);
$worker->unregisterWorker(); $worker->unregisterWorker();
} }
} }
@ -449,7 +509,7 @@ class Resque_Worker
* *
* @return array Array of Resque worker process IDs. * @return array Array of Resque worker process IDs.
*/ */
public function workerPids() public function workerPids(): array
{ {
$pids = []; $pids = [];
exec('ps -A -o pid,command | grep [r]esque', $cmdOutput); exec('ps -A -o pid,command | grep [r]esque', $cmdOutput);
@ -461,100 +521,122 @@ class Resque_Worker
/** /**
* Register this worker in Redis. * Register this worker in Redis.
* 48 hour TTL so we don't pollute the db on server termination. * 48 hour TTL so we don't pollute the redis db on server termination.
*
* @return void
*/ */
public function registerWorker() public function registerWorker(): void
{ {
Resque::redis()->sadd('workers', (string)$this); Resque::redis()->sadd('workers', (string)$this);
Resque::redis()->setex('worker:' . (string)$this . ':started', 172800, strftime('%a %b %d %H:%M:%S %Z %Y')); Resque::redis()->set(
'worker:' . (string)$this . ':started',
date('D M d H:i:s T Y'),
['ex' => Redis::DEFAULT_REDIS_TTL],
);
} }
/** /**
* Unregister this worker in Redis. (shutdown etc) * Unregister this worker in Redis. (shutdown etc)
*
* @return void
*/ */
public function unregisterWorker() public function unregisterWorker(): void
{ {
if (is_object($this->currentJob)) { if (is_object($this->currentJob)) {
$this->currentJob->fail(new Resque_Job_DirtyExitException); $this->currentJob->fail(new \Resque\Job\DirtyExitException());
} }
$id = (string)$this; $id = (string)$this;
Resque::redis()->srem('workers', $id); Resque::redis()->srem('workers', $id);
Resque::redis()->del('worker:' . $id); Resque::redis()->del('worker:' . $id);
Resque::redis()->del('worker:' . $id . ':started'); Resque::redis()->del('worker:' . $id . ':started');
Resque_Stat::clear('processed:' . $id); Stat::clear('processed:' . $id);
Resque_Stat::clear('failed:' . $id); Stat::clear('failed:' . $id);
} }
/** /**
* Tell Redis which job we're currently working on. * Tell Redis which job we're currently working on
*
* @param \Resque\Job\Job $job \Resque\Job\Job instance containing the job we're working on
*
* @return void
* *
* @param Resque_Job $job Resque_Job instance containing the job we're working on.
* @throws Resque_RedisException * @throws Resque_RedisException
*/ */
public function workingOn(Resque_Job $job) public function workingOn(\Resque\Job\Job $job): void
{ {
$job->worker = $this; $job->worker = $this;
$this->currentJob = $job; $this->currentJob = $job;
$job->updateStatus(Resque_Job_Status::STATUS_RUNNING); $job->updateStatus(\Resque\Job\Status::STATUS_RUNNING);
$data = json_encode([ $data = json_encode([
'queue' => $job->queue, 'queue' => $job->queue,
'run_at' => strftime('%a %b %d %H:%M:%S %Z %Y'), 'run_at' => date('D M d H:i:s T Y'),
'payload' => $job->payload 'payload' => $job->payload
]); ]);
Resque::redis()->set('worker:' . $job->worker, $data);
Resque::redis()->set(
'worker:' . $job->worker,
$data,
['ex' => Redis::DEFAULT_REDIS_TTL],
);
} }
/** /**
* Notify Redis that we've finished working on a job, clearing the working * Notify Redis that we've finished working on a job, clearing the working
* state and incrementing the job stats. * state and incrementing the job stats
*
* @return void
*/ */
public function doneWorking() public function doneWorking(): void
{ {
$this->currentJob = null; $this->currentJob = null;
Resque_Stat::incr('processed'); Stat::incr('processed');
Resque_Stat::incr('processed:' . (string)$this); Stat::incr('processed:' . (string)$this);
Resque::redis()->del('worker:' . (string)$this); Resque::redis()->del('worker:' . (string)$this);
} }
/** /**
* Generate a string representation of this worker. * Generate a string representation of this worker
* *
* @return string String identifier for this worker instance. * @return string String identifier for this worker instance
*/ */
public function __toString() public function __toString(): string
{ {
return $this->id; return (string) $this->id;
} }
/** /**
* Return an object describing the job this worker is currently working on. * Return an object describing the job this worker is currently working on
* *
* @return array Array with details of current job. * @return array Array with details of current job
*/ */
public function job(): array public function job(): array
{ {
$job = Resque::redis()->get('worker:' . $this); $job = Resque::redis()->get('worker:' . $this);
return $job ? json_decode($job, true) : []; return $job ? json_decode($job, true) : [];
} }
/** /**
* Get a statistic belonging to this worker. * Get a statistic belonging to this worker
* *
* @param string $stat Statistic to fetch. * @param string $stat Statistic to fetch.
*
* @return int Statistic value. * @return int Statistic value.
*/ */
public function getStat($stat) public function getStat(string $stat): int
{ {
return Resque_Stat::get($stat . ':' . $this); return \Resque\Stat::get($stat . ':' . $this);
} }
/** /**
* Inject the logging object into the worker * Inject the logging object into the worker
* *
* @param Psr\Log\LoggerInterface $logger * @param \Psr\Log\LoggerInterface $logger
*
* @return void
*/ */
public function setLogger(Psr\Log\LoggerInterface $logger) public function setLogger(\Psr\Log\LoggerInterface $logger): void
{ {
$this->logger = $logger; $this->logger = $logger;
} }

View file

@ -1,109 +0,0 @@
<?php
/**
* Resque_Job_Status tests.
*
* @package Resque/Tests
* @author Chris Boulton <chris@bigcommerce.com>
* @license http://www.opensource.org/licenses/mit-license.php
*/
class Resque_Tests_JobStatusTest extends Resque_Tests_TestCase
{
/**
* @var Resque_Worker
*/
protected $worker;
public function setUp()
{
parent::setUp();
// Register a worker to test with
$this->worker = new Resque_Worker('jobs');
$this->worker->setLogger(new Resque_Log());
}
public function testJobStatusCanBeTracked()
{
$token = Resque::enqueue('jobs', 'Test_Job', null, true);
$status = new Resque_Job_Status($token);
$this->assertTrue($status->isTracking());
}
public function testJobStatusIsReturnedViaJobInstance()
{
Resque::enqueue('jobs', 'Test_Job', null, true);
$job = Resque_Job::reserve('jobs');
$this->assertEquals(Resque_Job_Status::STATUS_WAITING, $job->getStatus());
}
public function testQueuedJobReturnsQueuedStatus()
{
$token = Resque::enqueue('jobs', 'Test_Job', null, true);
$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);
$job = $this->worker->reserve();
$this->worker->workingOn($job);
$status = new Resque_Job_Status($token);
$this->assertEquals(Resque_Job_Status::STATUS_RUNNING, $status->get());
}
public function testFailedJobReturnsFailedStatus()
{
$token = Resque::enqueue('jobs', 'Failing_Job', null, true);
$this->worker->work(0);
$status = new Resque_Job_Status($token);
$this->assertEquals(Resque_Job_Status::STATUS_FAILED, $status->get());
}
public function testCompletedJobReturnsCompletedStatus()
{
$token = Resque::enqueue('jobs', 'Test_Job', null, true);
$this->worker->work(0);
$status = new Resque_Job_Status($token);
$this->assertEquals(Resque_Job_Status::STATUS_COMPLETE, $status->get());
}
public function testStatusIsNotTrackedWhenToldNotTo()
{
$token = Resque::enqueue('jobs', 'Test_Job', null, false);
$status = new Resque_Job_Status($token);
$this->assertFalse($status->isTracking());
}
public function testStatusTrackingCanBeStopped()
{
Resque_Job_Status::create('test');
$status = new Resque_Job_Status('test');
$this->assertEquals(Resque_Job_Status::STATUS_WAITING, $status->get());
$status->stop();
$this->assertFalse($status->get());
}
public function testRecreatedJobWithTrackingStillTracksStatus()
{
$originalToken = Resque::enqueue('jobs', 'Test_Job', null, true);
$job = $this->worker->reserve();
// Mark this job as being worked on to ensure that the new status is still
// waiting.
$this->worker->workingOn($job);
// Now recreate it
$newToken = $job->recreate();
// Make sure we've got a new job returned
$this->assertNotEquals($originalToken, $newToken);
// Now check the status of the new job
$newJob = Resque_Job::reserve('jobs');
$this->assertEquals(Resque_Job_Status::STATUS_WAITING, $newJob->getStatus());
}
}

View file

@ -1,417 +0,0 @@
<?php
/**
* Resque_Job tests.
*
* @package Resque/Tests
* @author Chris Boulton <chris@bigcommerce.com>
* @license http://www.opensource.org/licenses/mit-license.php
*/
class Resque_Tests_JobTest extends Resque_Tests_TestCase
{
protected $worker;
public function setUp()
{
parent::setUp();
// Register a worker to test with
$this->worker = new Resque_Worker('jobs');
$this->worker->setLogger(new Resque_Log());
$this->worker->registerWorker();
}
public function testJobCanBeQueued()
{
$this->assertTrue((bool)Resque::enqueue('jobs', 'Test_Job'));
}
public function testQeueuedJobCanBeReserved()
{
Resque::enqueue('jobs', 'Test_Job');
$job = Resque_Job::reserve('jobs');
if ($job == false) {
$this->fail('Job could not be reserved.');
}
$this->assertEquals('jobs', $job->queue);
$this->assertEquals('Test_Job', $job->payload['class']);
}
/**
* @expectedException InvalidArgumentException
*/
public function testObjectArgumentsCannotBePassedToJob()
{
$args = new stdClass;
$args->test = 'somevalue';
Resque::enqueue('jobs', 'Test_Job', $args);
}
public function testQueuedJobReturnsExactSamePassedInArguments()
{
$args = [
'int' => 123,
'numArray' => [
1,
2,
],
'assocArray' => [
'key1' => 'value1',
'key2' => 'value2'
],
];
Resque::enqueue('jobs', 'Test_Job', $args);
$job = Resque_Job::reserve('jobs');
$this->assertEquals($args, $job->getArguments());
}
public function testAfterJobIsReservedItIsRemoved()
{
Resque::enqueue('jobs', 'Test_Job');
Resque_Job::reserve('jobs');
$this->assertFalse(Resque_Job::reserve('jobs'));
}
public function testRecreatedJobMatchesExistingJob()
{
$args = [
'int' => 123,
'numArray' => [
1,
2,
],
'assocArray' => [
'key1' => 'value1',
'key2' => 'value2'
],
];
Resque::enqueue('jobs', 'Test_Job', $args);
$job = Resque_Job::reserve('jobs');
// Now recreate it
$job->recreate();
$newJob = Resque_Job::reserve('jobs');
$this->assertEquals($job->payload['class'], $newJob->payload['class']);
$this->assertEquals($job->getArguments(), $newJob->getArguments());
}
public function testFailedJobExceptionsAreCaught()
{
$payload = [
'class' => 'Failing_Job',
'args' => null
];
$job = new Resque_Job('jobs', $payload);
$job->worker = $this->worker;
$this->worker->perform($job);
$this->assertEquals(1, Resque_Stat::get('failed'));
$this->assertEquals(1, Resque_Stat::get('failed:' . $this->worker));
}
/**
* @expectedException Resque_Exception
*/
public function testJobWithoutPerformMethodThrowsException()
{
Resque::enqueue('jobs', 'Test_Job_Without_Perform_Method');
$job = $this->worker->reserve();
$job->worker = $this->worker;
$job->perform();
}
/**
* @expectedException Resque_Exception
*/
public function testInvalidJobThrowsException()
{
Resque::enqueue('jobs', 'Invalid_Job');
$job = $this->worker->reserve();
$job->worker = $this->worker;
$job->perform();
}
public function testJobWithSetUpCallbackFiresSetUp()
{
$payload = [
'class' => 'Test_Job_With_SetUp',
'args' => [
'somevar',
'somevar2',
],
];
$job = new Resque_Job('jobs', $payload);
$job->perform();
$this->assertTrue(Test_Job_With_SetUp::$called);
}
public function testJobWithTearDownCallbackFiresTearDown()
{
$payload = [
'class' => 'Test_Job_With_TearDown',
'args' => [
'somevar',
'somevar2',
],
];
$job = new Resque_Job('jobs', $payload);
$job->perform();
$this->assertTrue(Test_Job_With_TearDown::$called);
}
public function testNamespaceNaming()
{
$fixture = [
['test' => 'more:than:one:with:', 'assertValue' => 'more:than:one:with:'],
['test' => 'more:than:one:without', 'assertValue' => 'more:than:one:without:'],
['test' => 'resque', 'assertValue' => 'resque:'],
['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');
$queue = 'jobs';
$payload = ['another_value'];
Resque::enqueue($queue, 'Test_Job_With_TearDown', $payload);
$this->assertEquals(Resque::queues(), ['jobs']);
$this->assertEquals(Resque::size($queue), 1);
Resque_Redis::prefix('resque');
$this->assertEquals(Resque::size($queue), 0);
}
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 = ['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 = ['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 = ['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 = ['Test_Job_Dequeue4', 'Test_Job_Dequeue1'];
$this->assertEquals(Resque::dequeue($queue, $test), 1);
$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 = ['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 = ['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');
Resque::enqueue($queue, 'Test_Job_Dequeue');
$this->assertEquals(Resque::size($queue), 2);
$test = ['Test_Job_Dequeue' => 'r4nD0mH4sh3dId'];
$this->assertEquals(Resque::dequeue($queue, $test), 0);
$this->assertEquals(Resque::size($queue), 2);
}
public function testDequeueItemWithArg()
{
$queue = 'jobs';
$arg = ['foo' => 1, 'bar' => 2];
Resque::enqueue($queue, 'Test_Job_Dequeue9');
Resque::enqueue($queue, 'Test_Job_Dequeue9', $arg);
$this->assertEquals(Resque::size($queue), 2);
$test = ['Test_Job_Dequeue9' => $arg];
$this->assertEquals(Resque::dequeue($queue, $test), 1);
#$this->assertEquals(Resque::size($queue), 1);
}
public function testDequeueSeveralItemsWithArgs()
{
// GIVEN
$queue = 'jobs';
$args = ['foo' => 1, 'bar' => 10];
$removeArgs = ['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, "Failed to add 3 items.");
// WHEN
$test = ['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()
{
$queue = 'jobs';
$arg = ['foo' => 1, 'bar' => 2];
$arg2 = ['bar' => 2, 'foo' => 1];
Resque::enqueue($queue, 'Test_Job_Dequeue');
Resque::enqueue($queue, 'Test_Job_Dequeue', $arg);
$this->assertEquals(Resque::size($queue), 2);
$test = ['Test_Job_Dequeue' => $arg2];
$this->assertEquals(Resque::dequeue($queue, $test), 1);
$this->assertEquals(Resque::size($queue), 1);
}
public function testDequeueItemWithiWrongArg()
{
$queue = 'jobs';
$arg = ['foo' => 1, 'bar' => 2];
$arg2 = ['foo' => 2, 'bar' => 3];
Resque::enqueue($queue, 'Test_Job_Dequeue');
Resque::enqueue($queue, 'Test_Job_Dequeue', $arg);
$this->assertEquals(Resque::size($queue), 2);
$test = ['Test_Job_Dequeue' => $arg2];
$this->assertEquals(Resque::dequeue($queue, $test), 0);
$this->assertEquals(Resque::size($queue), 2);
}
public function testUseDefaultFactoryToGetJobInstance()
{
$payload = [
'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 = [
'class' => 'Some_Job_Class',
'args' => [[]]
];
$job = new Resque_Job('jobs', $payload);
$factory = new Some_Stub_Factory();
$job->setJobFactory($factory);
$instance = $job->getInstance();
$this->assertInstanceOf('Resque_JobInterface', $instance);
}
}
class Some_Job_Class implements Resque_JobInterface
{
/**
* @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, $args, $queue)
{
return new Some_Job_Class();
}
}

View file

@ -1,43 +1,45 @@
<?php <?php
namespace Resque\Test;
/** /**
* Resque_Event tests. * \Resque\Event tests.
* *
* @package Resque/Tests * @package Resque/Tests
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Tests_EventTest extends Resque_Tests_TestCase class EventTest extends TestCase
{ {
private $callbacksHit = []; private $callbacksHit = [];
private $worker; private $worker;
public function setUp() public function setUp(): void
{ {
Test_Job::$called = false; TestJob::$called = false;
// Register a worker to test with // Register a worker to test with
$this->worker = new Resque_Worker('jobs'); $this->worker = new \Resque\Worker('jobs');
$this->worker->setLogger(new Resque_Log()); $this->worker->setLogger(new \Resque\Log());
$this->worker->registerWorker(); $this->worker->registerWorker();
} }
public function tearDown() public function tearDown(): void
{ {
Resque_Event::clearListeners(); \Resque\Event::clearListeners();
$this->callbacksHit = []; $this->callbacksHit = [];
} }
public function getEventTestJob() public function getEventTestJob()
{ {
$payload = [ $payload = [
'class' => 'Test_Job', 'class' => '\Resque\Test\TestJob',
'args' => [ 'args' => [
['somevar'], ['somevar'],
], ],
]; ];
$job = new Resque_Job('jobs', $payload); $job = new \Resque\Job\Job('jobs', $payload);
$job->worker = $this->worker; $job->worker = $this->worker;
return $job; return $job;
} }
@ -58,7 +60,7 @@ class Resque_Tests_EventTest extends Resque_Tests_TestCase
*/ */
public function testEventCallbacksFire($event, $callback) public function testEventCallbacksFire($event, $callback)
{ {
Resque_Event::listen($event, [$this, $callback]); \Resque\Event::listen($event, [$this, $callback]);
$job = $this->getEventTestJob(); $job = $this->getEventTestJob();
$this->worker->perform($job); $this->worker->perform($job);
@ -72,8 +74,8 @@ class Resque_Tests_EventTest extends Resque_Tests_TestCase
$event = 'beforeFork'; $event = 'beforeFork';
$callback = 'beforeForkEventCallback'; $callback = 'beforeForkEventCallback';
Resque_Event::listen($event, [$this, $callback]); \Resque\Event::listen($event, [$this, $callback]);
Resque::enqueue('jobs', 'Test_Job', [ \Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob', [
'somevar' 'somevar'
]); ]);
$this->getEventTestJob(); $this->getEventTestJob();
@ -86,8 +88,8 @@ class Resque_Tests_EventTest extends Resque_Tests_TestCase
$event = 'beforeEnqueue'; $event = 'beforeEnqueue';
$callback = 'beforeEnqueueEventCallback'; $callback = 'beforeEnqueueEventCallback';
Resque_Event::listen($event, [$this, $callback]); \Resque\Event::listen($event, [$this, $callback]);
Resque::enqueue('jobs', 'Test_Job', [ \Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob', [
'somevar' 'somevar'
]); ]);
$this->assertContains($callback, $this->callbacksHit, $event . ' callback (' . $callback . ') was not called'); $this->assertContains($callback, $this->callbacksHit, $event . ' callback (' . $callback . ') was not called');
@ -96,22 +98,22 @@ class Resque_Tests_EventTest extends Resque_Tests_TestCase
public function testBeforePerformEventCanStopWork() public function testBeforePerformEventCanStopWork()
{ {
$callback = 'beforePerformEventDontPerformCallback'; $callback = 'beforePerformEventDontPerformCallback';
Resque_Event::listen('beforePerform', [$this, $callback]); \Resque\Event::listen('beforePerform', [$this, $callback]);
$job = $this->getEventTestJob(); $job = $this->getEventTestJob();
$this->assertFalse($job->perform()); $this->assertFalse($job->perform());
$this->assertContains($callback, $this->callbacksHit, $callback . ' callback was not called'); $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'); $this->assertFalse(TestJob::$called, 'Job was still performed though Resque_Job_DontPerform was thrown');
} }
public function testBeforeEnqueueEventStopsJobCreation() public function testBeforeEnqueueEventStopsJobCreation()
{ {
$callback = 'beforeEnqueueEventDontCreateCallback'; $callback = 'beforeEnqueueEventDontCreateCallback';
Resque_Event::listen('beforeEnqueue', [$this, $callback]); \Resque\Event::listen('beforeEnqueue', [$this, $callback]);
Resque_Event::listen('afterEnqueue', [$this, 'afterEnqueueEventCallback']); \Resque\Event::listen('afterEnqueue', [$this, 'afterEnqueueEventCallback']);
$result = Resque::enqueue('test_job', 'TestClass'); $result = \Resque\Resque::enqueue('jobs', '\Resque\Test\TestClass');
$this->assertContains($callback, $this->callbacksHit, $callback . ' callback was not called'); $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->assertNotContains('afterEnqueueEventCallback', $this->callbacksHit, 'afterEnqueue was still called, even though it should not have been');
$this->assertFalse($result); $this->assertFalse($result);
@ -122,8 +124,8 @@ class Resque_Tests_EventTest extends Resque_Tests_TestCase
$callback = 'afterEnqueueEventCallback'; $callback = 'afterEnqueueEventCallback';
$event = 'afterEnqueue'; $event = 'afterEnqueue';
Resque_Event::listen($event, [$this, $callback]); \Resque\Event::listen($event, [$this, $callback]);
Resque::enqueue('jobs', 'Test_Job', [ \Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob', [
'somevar' 'somevar'
]); ]);
$this->assertContains($callback, $this->callbacksHit, $event . ' callback (' . $callback . ') was not called'); $this->assertContains($callback, $this->callbacksHit, $event . ' callback (' . $callback . ') was not called');
@ -134,8 +136,8 @@ class Resque_Tests_EventTest extends Resque_Tests_TestCase
$callback = 'beforePerformEventCallback'; $callback = 'beforePerformEventCallback';
$event = 'beforePerform'; $event = 'beforePerform';
Resque_Event::listen($event, [$this, $callback]); \Resque\Event::listen($event, [$this, $callback]);
Resque_Event::stopListening($event, [$this, $callback]); \Resque\Event::stopListening($event, [$this, $callback]);
$job = $this->getEventTestJob(); $job = $this->getEventTestJob();
$this->worker->perform($job); $this->worker->perform($job);
@ -149,20 +151,20 @@ class Resque_Tests_EventTest extends Resque_Tests_TestCase
public function beforePerformEventDontPerformCallback() public function beforePerformEventDontPerformCallback()
{ {
$this->callbacksHit[] = __FUNCTION__; $this->callbacksHit[] = __FUNCTION__;
throw new Resque_Job_DontPerform(); throw new \Resque\Job\DontPerform();
} }
public function beforeEnqueueEventDontCreateCallback() public function beforeEnqueueEventDontCreateCallback()
{ {
$this->callbacksHit[] = __FUNCTION__; $this->callbacksHit[] = __FUNCTION__;
throw new Resque_Job_DontCreate(); throw new \Resque\Job\DontCreate();
} }
public function assertValidEventCallback($function, $job) public function assertValidEventCallback($function, $job)
{ {
$this->callbacksHit[] = $function; $this->callbacksHit[] = $function;
if (!$job instanceof Resque_Job) { if (!$job instanceof \Resque\Job\Job) {
$this->fail('Callback job argument is not an instance of Resque_Job'); $this->fail('Callback job argument is not an instance of \Resque\Job\Job');
} }
$args = $job->getArguments(); $args = $job->getArguments();
$this->assertEquals($args[0], 'somevar'); $this->assertEquals($args[0], 'somevar');
@ -171,7 +173,7 @@ class Resque_Tests_EventTest extends Resque_Tests_TestCase
public function afterEnqueueEventCallback($class, $args) public function afterEnqueueEventCallback($class, $args)
{ {
$this->callbacksHit[] = __FUNCTION__; $this->callbacksHit[] = __FUNCTION__;
$this->assertEquals('Test_Job', $class); $this->assertEquals('\Resque\Test\TestJob', $class);
$this->assertEquals([ $this->assertEquals([
'somevar', 'somevar',
], $args); ], $args);

View file

@ -0,0 +1,110 @@
<?php
namespace Resque\Test;
/**
* \Resque\Job\Status tests.
*
* @package Resque/Tests
* @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php
*/
class JobStatusTest extends TestCase
{
/**
* @var \Resque\Worker
*/
protected $worker;
public function setUp(): void
{
parent::setUp();
// Register a worker to test with
$this->worker = new \Resque\Worker('jobs');
$this->worker->setLogger(new \Resque\Log());
}
public function testJobStatusCanBeTracked()
{
$token = \Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob', null, true);
$status = new \Resque\Job\Status($token);
$this->assertTrue($status->isTracking());
}
public function testJobStatusIsReturnedViaJobInstance()
{
\Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob', null, true);
$job = \Resque\Job\Job::reserve('jobs');
$this->assertEquals(\Resque\Job\Status::STATUS_WAITING, $job->getStatus());
}
public function testQueuedJobReturnsQueuedStatus()
{
$token = \Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob', null, true);
$status = new \Resque\Job\Status($token);
$this->assertEquals(\Resque\Job\Status::STATUS_WAITING, $status->get());
}
public function testRunningJobReturnsRunningStatus()
{
$token = \Resque\Resque::enqueue('jobs', '\Resque\Test\FailingJob', null, true);
$job = $this->worker->reserve();
$this->worker->workingOn($job);
$status = new \Resque\Job\Status($token);
$this->assertEquals(\Resque\Job\Status::STATUS_RUNNING, $status->get());
}
public function testFailedJobReturnsFailedStatus()
{
$token = \Resque\Resque::enqueue('jobs', '\Resque\Test\FailingJob', null, true);
$this->worker->work(0);
$status = new \Resque\Job\Status($token);
$this->assertEquals(\Resque\Job\Status::STATUS_FAILED, $status->get());
}
public function testCompletedJobReturnsCompletedStatus()
{
$token = \Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob', null, true);
$this->worker->work(0);
$status = new \Resque\Job\Status($token);
$this->assertEquals(\Resque\Job\Status::STATUS_COMPLETE, $status->get());
}
public function testStatusIsNotTrackedWhenToldNotTo()
{
$token = \Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob', null, false);
$status = new \Resque\Job\Status($token);
$this->assertFalse($status->isTracking());
}
public function testStatusTrackingCanBeStopped()
{
\Resque\Job\Status::create('test');
$status = new \Resque\Job\Status('test');
$this->assertEquals(\Resque\Job\Status::STATUS_WAITING, $status->get());
$status->stop();
$this->assertFalse($status->get());
}
public function testRecreatedJobWithTrackingStillTracksStatus()
{
$originalToken = \Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob', null, true);
$job = $this->worker->reserve();
// Mark this job as being worked on to ensure that the new status is still
// waiting.
$this->worker->workingOn($job);
// Now recreate it
$newToken = $job->recreate();
// Make sure we've got a new job returned
$this->assertNotEquals($originalToken, $newToken);
// Now check the status of the new job
$newJob = \Resque\Job\Job::reserve('jobs');
$this->assertEquals(\Resque\Job\Status::STATUS_WAITING, $newJob->getStatus());
}
}

View file

@ -0,0 +1,431 @@
<?php
namespace Resque\Test;
/**
* ResqueJob tests.
*
* @package Resque/Tests
* @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php
*/
class JobTest extends TestCase
{
protected $worker;
public function setUp(): void
{
parent::setUp();
// Register a worker to test with
$this->worker = new \Resque\Worker('jobs');
$this->worker->setLogger(new \Resque\Log());
$this->worker->registerWorker();
}
public function testJobCanBeQueued()
{
$this->assertTrue((bool)\Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob'));
}
public function testQeueuedJobCanBeReserved()
{
\Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob');
$job = \Resque\Job\Job::reserve('jobs');
if (is_null($job)) {
$this->fail('Job could not be reserved.');
}
$this->assertEquals('jobs', $job->queue);
$this->assertEquals('\Resque\Test\TestJob', $job->payload['class']);
}
/**
* @expectedException \InvalidArgumentException
*/
public function testObjectArgumentsCannotBePassedToJob()
{
$this->expectException(\InvalidArgumentException::class);
$args = new \stdClass();
$args->test = 'somevalue';
\Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob', $args);
}
public function testQueuedJobReturnsExactSamePassedInArguments()
{
$args = [
'int' => 123,
'numArray' => [
1,
2,
],
'assocArray' => [
'key1' => 'value1',
'key2' => 'value2'
],
];
\Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob', $args);
$job = \Resque\Job\Job::reserve('jobs');
$this->assertEquals($args, $job->getArguments());
}
public function testAfterJobIsReservedItIsRemoved()
{
\Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob');
\Resque\Job\Job::reserve('jobs');
$this->assertNull(\Resque\Job\Job::reserve('jobs'));
}
public function testRecreatedJobMatchesExistingJob()
{
$args = [
'int' => 123,
'numArray' => [
1,
2,
],
'assocArray' => [
'key1' => 'value1',
'key2' => 'value2'
],
];
\Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob', $args);
$job = \Resque\Job\Job::reserve('jobs');
// Now recreate it
$job->recreate();
$newJob = \Resque\Job\Job::reserve('jobs');
$this->assertEquals($job->payload['class'], $newJob->payload['class']);
$this->assertEquals($job->getArguments(), $newJob->getArguments());
}
public function testFailedJobExceptionsAreCaught()
{
$payload = [
'class' => '\Resque\Test\FailingJob',
'args' => null
];
$job = new \Resque\Job\Job('jobs', $payload);
$job->worker = $this->worker;
$this->worker->perform($job);
$this->assertEquals(1, \Resque\Stat::get('failed'));
$this->assertEquals(1, \Resque\Stat::get('failed:' . $this->worker));
}
/**
* @expectedException \Resque\Exception
*/
public function testJobWithoutPerformMethodThrowsException()
{
$this->expectException(\Resque\Exception::class);
\Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob_Without_Perform_Method');
$job = $this->worker->reserve();
$job->worker = $this->worker;
$job->perform();
}
/**
* @expectedException \Resque\Exception
*/
public function testInvalidJobThrowsException()
{
$this->expectException(\Resque\Exception::class);
\Resque\Resque::enqueue('jobs', '\Resque\Test\InvalidJob');
$job = $this->worker->reserve();
$job->worker = $this->worker;
$job->perform();
}
public function testJobWithSetUpCallbackFiresSetUp()
{
$payload = [
'class' => '\Resque\Test\TestJobWithSetUp',
'args' => [
'somevar',
'somevar2',
],
];
$job = new \Resque\Job\Job('jobs', $payload);
$job->perform();
$this->assertTrue(TestJobWithSetUp::$called);
}
public function testJobWithTearDownCallbackFiresTearDown()
{
$payload = [
'class' => '\Resque\Test\TestJobWithTearDown',
'args' => [
'somevar',
'somevar2',
],
];
$job = new \Resque\Job\Job('jobs', $payload);
$job->perform();
$this->assertTrue(TestJobWithTearDown::$called);
}
public function testNamespaceNaming()
{
$fixture = [
['test' => 'more:than:one:with:', 'assertValue' => 'more:than:one:with:'],
['test' => 'more:than:one:without', 'assertValue' => 'more:than:one:without:'],
['test' => 'resque', 'assertValue' => 'resque:'],
['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');
$queue = 'jobs';
$payload = ['another_value'];
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobWithTearDown', $payload);
$this->assertEquals(\Resque\Resque::queues(), ['jobs']);
$this->assertEquals(\Resque\Resque::size($queue), 1);
\Resque\Redis::prefix('resque');
$this->assertEquals(\Resque\Resque::size($queue), 0);
}
public function testDequeueAll()
{
$queue = 'jobs';
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobDequeue');
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobDequeue');
$this->assertEquals(\Resque\Resque::size($queue), 2);
$this->assertEquals(\Resque\Resque::dequeue($queue), 2);
$this->assertEquals(\Resque\Resque::size($queue), 0);
}
public function testDequeueMakeSureNotDeleteOthers()
{
$queue = 'jobs';
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobDequeue');
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobDequeue');
$other_queue = 'other_jobs';
\Resque\Resque::enqueue($other_queue, '\Resque\Test\TestJobDequeue');
\Resque\Resque::enqueue($other_queue, '\Resque\Test\TestJobDequeue');
$this->assertEquals(\Resque\Resque::size($queue), 2);
$this->assertEquals(\Resque\Resque::size($other_queue), 2);
$this->assertEquals(\Resque\Resque::dequeue($queue), 2);
$this->assertEquals(\Resque\Resque::size($queue), 0);
$this->assertEquals(\Resque\Resque::size($other_queue), 2);
}
public function testDequeueSpecificItem()
{
$queue = 'jobs';
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobDequeue1');
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobDequeue2');
$this->assertEquals(\Resque\Resque::size($queue), 2);
$test = ['\Resque\Test\TestJobDequeue2'];
$this->assertEquals(\Resque\Resque::dequeue($queue, $test), 1);
$this->assertEquals(\Resque\Resque::size($queue), 1);
}
public function testDequeueSpecificMultipleItems()
{
$queue = 'jobs';
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJob_Dequeue1');
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJob_Dequeue2');
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJob_Dequeue3');
$this->assertEquals(\Resque\Resque::size($queue), 3);
$test = ['\Resque\Test\TestJob_Dequeue2', '\Resque\Test\TestJob_Dequeue3'];
$this->assertEquals(\Resque\Resque::dequeue($queue, $test), 2);
$this->assertEquals(\Resque\Resque::size($queue), 1);
}
public function testDequeueNonExistingItem()
{
$queue = 'jobs';
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJob_Dequeue1');
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJob_Dequeue2');
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJob_Dequeue3');
$this->assertEquals(\Resque\Resque::size($queue), 3);
$test = ['\Resque\Test\TestJob_Dequeue4'];
$this->assertEquals(\Resque\Resque::dequeue($queue, $test), 0);
$this->assertEquals(\Resque\Resque::size($queue), 3);
}
public function testDequeueNonExistingItem2()
{
$queue = 'jobs';
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJob_Dequeue1');
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJob_Dequeue2');
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJob_Dequeue3');
$this->assertEquals(\Resque\Resque::size($queue), 3);
$test = ['\Resque\Test\TestJob_Dequeue4', '\Resque\Test\TestJob_Dequeue1'];
$this->assertEquals(\Resque\Resque::dequeue($queue, $test), 1);
$this->assertEquals(\Resque\Resque::size($queue), 2);
}
public function testDequeueItemID()
{
$queue = 'jobs';
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJob_Dequeue');
$qid = \Resque\Resque::enqueue($queue, '\Resque\Test\TestJob_Dequeue');
$this->assertEquals(\Resque\Resque::size($queue), 2);
$test = ['\Resque\Test\TestJob_Dequeue' => $qid];
$this->assertEquals(\Resque\Resque::dequeue($queue, $test), 1);
$this->assertEquals(\Resque\Resque::size($queue), 1);
}
public function testDequeueWrongItemID()
{
$queue = 'jobs';
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJob_Dequeue');
$qid = \Resque\Resque::enqueue($queue, '\Resque\Test\TestJob_Dequeue');
$this->assertEquals(\Resque\Resque::size($queue), 2);
#qid right but class name is wrong
$test = ['\Resque\Test\TestJob_Dequeue1' => $qid];
$this->assertEquals(\Resque\Resque::dequeue($queue, $test), 0);
$this->assertEquals(\Resque\Resque::size($queue), 2);
}
public function testDequeueWrongItemID2()
{
$queue = 'jobs';
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJob_Dequeue');
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJob_Dequeue');
$this->assertEquals(\Resque\Resque::size($queue), 2);
$test = ['\Resque\Test\TestJob_Dequeue' => 'r4nD0mH4sh3dId'];
$this->assertEquals(\Resque\Resque::dequeue($queue, $test), 0);
$this->assertEquals(\Resque\Resque::size($queue), 2);
}
public function testDequeueItemWithArg()
{
$queue = 'jobs';
$arg = ['foo' => 1, 'bar' => 2];
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobDequeue9');
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobDequeue9', $arg);
$this->assertEquals(\Resque\Resque::size($queue), 2);
$test = ['\Resque\Test\TestJobDequeue9' => $arg];
$this->assertEquals(\Resque\Resque::dequeue($queue, $test), 1);
#$this->assertEquals(\Resque\Resque::size($queue), 1);
}
public function testDequeueSeveralItemsWithArgs()
{
// GIVEN
$queue = 'jobs';
$args = ['foo' => 1, 'bar' => 10];
$removeArgs = ['foo' => 1, 'bar' => 2];
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobDequeue9', $args);
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobDequeue9', $removeArgs);
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobDequeue9', $removeArgs);
$this->assertEquals(\Resque\Resque::size($queue), 3, "Failed to add 3 items.");
// WHEN
$test = ['\Resque\Test\TestJobDequeue9' => $removeArgs];
$removedItems = \Resque\Resque::dequeue($queue, $test);
// THEN
$this->assertEquals($removedItems, 2);
$this->assertEquals(\Resque\Resque::size($queue), 1);
$item = \Resque\Resque::pop($queue);
$this->assertIsArray($item['args']);
$this->assertEquals(10, $item['args'][0]['bar'], 'Wrong items were dequeued from queue!');
}
public function testDequeueItemWithUnorderedArg()
{
$queue = 'jobs';
$arg = ['foo' => 1, 'bar' => 2];
$arg2 = ['bar' => 2, 'foo' => 1];
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobDequeue');
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobDequeue', $arg);
$this->assertEquals(\Resque\Resque::size($queue), 2);
$test = ['\Resque\Test\TestJobDequeue' => $arg2];
$this->assertEquals(\Resque\Resque::dequeue($queue, $test), 1);
$this->assertEquals(\Resque\Resque::size($queue), 1);
}
public function testDequeueItemWithiWrongArg()
{
$queue = 'jobs';
$arg = ['foo' => 1, 'bar' => 2];
$arg2 = ['foo' => 2, 'bar' => 3];
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobDequeue');
\Resque\Resque::enqueue($queue, '\Resque\Test\TestJobDequeue', $arg);
$this->assertEquals(\Resque\Resque::size($queue), 2);
$test = ['\Resque\Test\TestJobDequeue' => $arg2];
$this->assertEquals(\Resque\Resque::dequeue($queue, $test), 0);
$this->assertEquals(\Resque\Resque::size($queue), 2);
}
public function testUseDefaultFactoryToGetJobInstance()
{
$payload = [
'class' => '\Resque\Test\SomeJobClass',
'args' => null
];
$job = new \Resque\Job\Job('jobs', $payload);
$instance = $job->getInstance();
$this->assertInstanceOf('\Resque\Test\SomeJobClass', $instance);
}
public function testUseFactoryToGetJobInstance()
{
$payload = [
'class' => 'SomeJobClass',
'args' => [[]]
];
$job = new \Resque\Job\Job('jobs', $payload);
$factory = new Some_Stub_Factory();
$job->setJobFactory($factory);
$instance = $job->getInstance();
$this->assertInstanceOf('\Resque\Job\JobInterface', $instance);
}
}
class SomeJobClass implements \Resque\Job\JobInterface
{
public static $called = false;
public $args = false;
public $queue;
public $job;
/**
* @return bool
*/
public function perform()
{
return true;
}
}
class Some_Stub_Factory implements \Resque\Job\FactoryInterface
{
public static $called = false;
public $args = false;
public $queue;
public $job;
/**
* @param $className
* @param array $args
* @param $queue
* @return \Resque\Job\JobInterface
*/
public function create($className, $args, $queue)
{
return new SomeJobClass();
}
}

View file

@ -1,18 +1,20 @@
<?php <?php
namespace Resque\Test;
/** /**
* Resque_Log tests. * \Resque\Log tests.
* *
* @package Resque/Tests * @package Resque/Tests
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Tests_LogTest extends Resque_Tests_TestCase class LogTest extends TestCase
{ {
public function testLogInterpolate() public function testLogInterpolate()
{ {
$logger = new Resque_Log(); $logger = new \Resque\Log();
$actual = $logger->interpolate('string {replace}', ['replace' => 'value']); $actual = $logger->interpolate('string {replace}', ['replace' => 'value']);
$expected = 'string value'; $expected = 'string value';
@ -21,7 +23,7 @@ class Resque_Tests_LogTest extends Resque_Tests_TestCase
public function testLogInterpolateMutiple() public function testLogInterpolateMutiple()
{ {
$logger = new Resque_Log(); $logger = new \Resque\Log();
$actual = $logger->interpolate( $actual = $logger->interpolate(
'string {replace1} {replace2}', 'string {replace1} {replace2}',
['replace1' => 'value1', 'replace2' => 'value2'] ['replace1' => 'value1', 'replace2' => 'value2']

View file

@ -1,18 +1,25 @@
<?php <?php
namespace Resque\Test;
/** /**
* Resque_Event tests. * Resque_Event tests.
* *
* @package Resque/Tests * @package Resque/Tests
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Tests_RedisTest extends Resque_Tests_TestCase class RedisTest extends TestCase
{ {
public function testRedisGetSet() public function testRedisGetSet()
{ {
$this->redis->set("testKey", 24); $this->redis->set(
'testKey',
24,
['ex' => \Resque\Redis::DEFAULT_REDIS_TTL],
);
$val = $this->redis->get("testKey"); $val = $this->redis->get("testKey");
$this->assertEquals(24, $val); $this->assertEquals(24, $val);
} }
@ -28,14 +35,14 @@ class Resque_Tests_RedisTest extends Resque_Tests_TestCase
// Input , Expected output // Input , Expected output
['', [ ['', [
'localhost', 'localhost',
Resque_Redis::DEFAULT_PORT, \Resque\Redis::DEFAULT_PORT,
false, false,
false, false, false, false,
[], [],
]], ]],
['localhost', [ ['localhost', [
'localhost', 'localhost',
Resque_Redis::DEFAULT_PORT, \Resque\Redis::DEFAULT_PORT,
false, false,
false, false, false, false,
[], [],
@ -56,14 +63,14 @@ class Resque_Tests_RedisTest extends Resque_Tests_TestCase
]], ]],
['redis://foobar', [ ['redis://foobar', [
'foobar', 'foobar',
Resque_Redis::DEFAULT_PORT, \Resque\Redis::DEFAULT_PORT,
false, false,
false, false, false, false,
[], [],
]], ]],
['redis://foobar/', [ ['redis://foobar/', [
'foobar', 'foobar',
Resque_Redis::DEFAULT_PORT, \Resque\Redis::DEFAULT_PORT,
false, false,
false, false, false, false,
[], [],
@ -175,18 +182,20 @@ class Resque_Tests_RedisTest extends Resque_Tests_TestCase
*/ */
public function testParsingValidDsnString($dsn, $expected) public function testParsingValidDsnString($dsn, $expected)
{ {
$result = Resque_Redis::parseDsn($dsn); $result = \Resque\Redis::parseDsn($dsn);
$this->assertEquals($expected, $result); $this->assertEquals($expected, $result);
} }
/** /**
* @dataProvider bogusDsnStringProvider * @dataProvider bogusDsnStringProvider
* @expectedException InvalidArgumentException *
* @expectedException \InvalidArgumentException
*
* @param $dsn * @param $dsn
*/ */
public function testParsingBogusDsnStringThrowsException($dsn) public function testParsingBogusDsnStringThrowsException($dsn)
{ {
// The next line should throw an InvalidArgumentException $this->expectException(\InvalidArgumentException::class);
Resque_Redis::parseDsn($dsn); \Resque\Redis::parseDsn($dsn);
} }
} }

View file

@ -1,51 +1,53 @@
<?php <?php
namespace Resque\Test;
/** /**
* Resque_Stat tests. * Resque\Stat tests.
* *
* @package Resque/Tests * @package Resque/Tests
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Tests_StatTest extends Resque_Tests_TestCase class StatTest extends TestCase
{ {
public function testStatCanBeIncremented() public function testStatCanBeIncremented()
{ {
Resque_Stat::incr('test_incr'); \Resque\Stat::incr('test_incr');
Resque_Stat::incr('test_incr'); \Resque\Stat::incr('test_incr');
$this->assertEquals(2, $this->redis->get('resque:stat:test_incr')); $this->assertEquals(2, $this->redis->get('resque:stat:test_incr'));
} }
public function testStatCanBeIncrementedByX() public function testStatCanBeIncrementedByX()
{ {
Resque_Stat::incr('test_incrX', 10); \Resque\Stat::incr('test_incrX', 10);
Resque_Stat::incr('test_incrX', 11); \Resque\Stat::incr('test_incrX', 11);
$this->assertEquals(21, $this->redis->get('resque:stat:test_incrX')); $this->assertEquals(21, $this->redis->get('resque:stat:test_incrX'));
} }
public function testStatCanBeDecremented() public function testStatCanBeDecremented()
{ {
Resque_Stat::incr('test_decr', 22); \Resque\Stat::incr('test_decr', 22);
Resque_Stat::decr('test_decr'); \Resque\Stat::decr('test_decr');
$this->assertEquals(21, $this->redis->get('resque:stat:test_decr')); $this->assertEquals(21, $this->redis->get('resque:stat:test_decr'));
} }
public function testStatCanBeDecrementedByX() public function testStatCanBeDecrementedByX()
{ {
Resque_Stat::incr('test_decrX', 22); \Resque\Stat::incr('test_decrX', 22);
Resque_Stat::decr('test_decrX', 11); \Resque\Stat::decr('test_decrX', 11);
$this->assertEquals(11, $this->redis->get('resque:stat:test_decrX')); $this->assertEquals(11, $this->redis->get('resque:stat:test_decrX'));
} }
public function testGetStatByName() public function testGetStatByName()
{ {
Resque_Stat::incr('test_get', 100); \Resque\Stat::incr('test_get', 100);
$this->assertEquals(100, Resque_Stat::get('test_get')); $this->assertEquals(100, \Resque\Stat::get('test_get'));
} }
public function testGetUnknownStatReturns0() public function testGetUnknownStatReturns0()
{ {
$this->assertEquals(0, Resque_Stat::get('test_get_unknown')); $this->assertEquals(0, \Resque\Stat::get('test_get_unknown'));
} }
} }

View file

@ -1,30 +1,31 @@
<?php <?php
namespace Resque\Test;
/** /**
* Resque test case class. Contains setup and teardown methods. * Resque test case class. Contains setup and teardown methods.
* *
* @package Resque/Tests * @package Resque/Tests
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class TestCase extends \PHPUnit\Framework\TestCase
class Resque_Tests_TestCase extends PHPUnit\Framework\TestCase
{ {
protected $resque; protected $resque;
protected $redis; protected $redis;
public static function setUpBeforeClass() public static function setUpBeforeClass(): void
{ {
date_default_timezone_set('UTC'); date_default_timezone_set('UTC');
} }
public function setUp() public function setUp(): void
{ {
// Setup redis connection for testing. // Setup redis connection for testing.
global $redisTestServer; global $redisTestServer;
$this->redis = new Credis_Client($redisTestServer, '6379'); $this->redis = new \Credis_Client($redisTestServer, '6379');
Resque::setBackend($redisTestServer); \Resque\Resque::setBackend($redisTestServer);
$this->redis->flushAll(); $this->redis->flushAll();
} }
} }

View file

@ -1,19 +1,21 @@
<?php <?php
namespace Resque\Test;
/** /**
* Resque_Worker tests. * \Resque\Worker tests.
* *
* @package Resque/Tests * @package Resque/Tests
* @author Chris Boulton <chris@bigcommerce.com> * @author Daniel Mason <daniel@m2.nz>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Resque_Tests_WorkerTest extends Resque_Tests_TestCase class WorkerTest extends TestCase
{ {
public function testWorkerRegistersInList() public function testWorkerRegistersInList()
{ {
$worker = new Resque_Worker('*'); $worker = new \Resque\Worker('*');
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->registerWorker(); $worker->registerWorker();
// Make sure the worker is in the list // Make sure the worker is in the list
@ -25,76 +27,76 @@ class Resque_Tests_WorkerTest extends Resque_Tests_TestCase
$num = 3; $num = 3;
// Register a few workers // Register a few workers
for ($i = 0; $i < $num; ++$i) { for ($i = 0; $i < $num; ++$i) {
$worker = new Resque_Worker('queue_' . $i); $worker = new \Resque\Worker('queue_' . $i);
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->registerWorker(); $worker->registerWorker();
} }
// Now try to get them // Now try to get them
$this->assertEquals($num, count(Resque_Worker::all())); $this->assertEquals($num, count(\Resque\Worker::all()));
} }
public function testGetWorkerById() public function testGetWorkerById()
{ {
$worker = new Resque_Worker('*'); $worker = new \Resque\Worker('*');
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->registerWorker(); $worker->registerWorker();
$newWorker = Resque_Worker::find((string)$worker); $newWorker = \Resque\Worker::find((string)$worker);
$this->assertEquals((string)$worker, (string)$newWorker); $this->assertEquals((string)$worker, (string)$newWorker);
} }
public function testInvalidWorkerDoesNotExist() public function testInvalidWorkerDoesNotExist()
{ {
$this->assertFalse(Resque_Worker::exists('blah')); $this->assertFalse(\Resque\Worker::exists('blah'));
} }
public function testWorkerCanUnregister() public function testWorkerCanUnregister()
{ {
$worker = new Resque_Worker('*'); $worker = new \Resque\Worker('*');
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->registerWorker(); $worker->registerWorker();
$worker->unregisterWorker(); $worker->unregisterWorker();
$this->assertFalse(Resque_Worker::exists((string)$worker)); $this->assertFalse(\Resque\Worker::exists((string)$worker));
$this->assertEquals([], Resque_Worker::all()); $this->assertEquals([], \Resque\Worker::all());
$this->assertEquals([], $this->redis->smembers('resque:workers')); $this->assertEquals([], $this->redis->smembers('resque:workers'));
} }
public function testPausedWorkerDoesNotPickUpJobs() public function testPausedWorkerDoesNotPickUpJobs()
{ {
$worker = new Resque_Worker('*'); $worker = new \Resque\Worker('*');
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->pauseProcessing(); $worker->pauseProcessing();
Resque::enqueue('jobs', 'Test_Job'); \Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob');
$worker->work(0); $worker->work(0);
$worker->work(0); $worker->work(0);
$this->assertEquals(0, Resque_Stat::get('processed')); $this->assertEquals(0, \Resque\Stat::get('processed'));
} }
public function testResumedWorkerPicksUpJobs() public function testResumedWorkerPicksUpJobs()
{ {
$worker = new Resque_Worker('*'); $worker = new \Resque\Worker('*');
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->pauseProcessing(); $worker->pauseProcessing();
Resque::enqueue('jobs', 'Test_Job'); \Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob');
$worker->work(0); $worker->work(0);
$this->assertEquals(0, Resque_Stat::get('processed')); $this->assertEquals(0, \Resque\Stat::get('processed'));
$worker->unPauseProcessing(); $worker->unPauseProcessing();
$worker->work(0); $worker->work(0);
$this->assertEquals(1, Resque_Stat::get('processed')); $this->assertEquals(1, \Resque\Stat::get('processed'));
} }
public function testWorkerCanWorkOverMultipleQueues() public function testWorkerCanWorkOverMultipleQueues()
{ {
$worker = new Resque_Worker([ $worker = new \Resque\Worker([
'queue1', 'queue1',
'queue2' 'queue2'
]); ]);
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->registerWorker(); $worker->registerWorker();
Resque::enqueue('queue1', 'Test_Job_1'); \Resque\Resque::enqueue('queue1', '\Resque\Test\TestJob_1');
Resque::enqueue('queue2', 'Test_Job_2'); \Resque\Resque::enqueue('queue2', '\Resque\Test\TestJob_2');
$job = $worker->reserve(); $job = $worker->reserve();
$this->assertEquals('queue1', $job->queue); $this->assertEquals('queue1', $job->queue);
@ -105,18 +107,18 @@ class Resque_Tests_WorkerTest extends Resque_Tests_TestCase
public function testWorkerWorksQueuesInSpecifiedOrder() public function testWorkerWorksQueuesInSpecifiedOrder()
{ {
$worker = new Resque_Worker([ $worker = new \Resque\Worker([
'high', 'high',
'medium', 'medium',
'low' 'low'
]); ]);
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->registerWorker(); $worker->registerWorker();
// Queue the jobs in a different order // Queue the jobs in a different order
Resque::enqueue('low', 'Test_Job_1'); \Resque\Resque::enqueue('low', '\Resque\Test\TestJob_1');
Resque::enqueue('high', 'Test_Job_2'); \Resque\Resque::enqueue('high', '\Resque\Test\TestJob_2');
Resque::enqueue('medium', 'Test_Job_3'); \Resque\Resque::enqueue('medium', '\Resque\Test\TestJob_3');
// Now check we get the jobs back in the right order // Now check we get the jobs back in the right order
$job = $worker->reserve(); $job = $worker->reserve();
@ -131,12 +133,12 @@ class Resque_Tests_WorkerTest extends Resque_Tests_TestCase
public function testWildcardQueueWorkerWorksAllQueues() public function testWildcardQueueWorkerWorksAllQueues()
{ {
$worker = new Resque_Worker('*'); $worker = new \Resque\Worker('*');
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->registerWorker(); $worker->registerWorker();
Resque::enqueue('queue1', 'Test_Job_1'); \Resque\Resque::enqueue('queue1', '\Resque\Test\TestJob_1');
Resque::enqueue('queue2', 'Test_Job_2'); \Resque\Resque::enqueue('queue2', '\Resque\Test\TestJob_2');
$job = $worker->reserve(); $job = $worker->reserve();
$this->assertEquals('queue1', $job->queue); $this->assertEquals('queue1', $job->queue);
@ -147,19 +149,19 @@ class Resque_Tests_WorkerTest extends Resque_Tests_TestCase
public function testWorkerDoesNotWorkOnUnknownQueues() public function testWorkerDoesNotWorkOnUnknownQueues()
{ {
$worker = new Resque_Worker('queue1'); $worker = new \Resque\Worker('queue1');
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->registerWorker(); $worker->registerWorker();
Resque::enqueue('queue2', 'Test_Job'); \Resque\Resque::enqueue('queue2', '\Resque\Test\TestJob');
$this->assertFalse($worker->reserve()); $this->assertFalse($worker->reserve());
} }
public function testWorkerClearsItsStatusWhenNotWorking() public function testWorkerClearsItsStatusWhenNotWorking()
{ {
Resque::enqueue('jobs', 'Test_Job'); \Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob');
$worker = new Resque_Worker('jobs'); $worker = new \Resque\Worker('jobs');
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$job = $worker->reserve(); $job = $worker->reserve();
$worker->workingOn($job); $worker->workingOn($job);
$worker->doneWorking(); $worker->doneWorking();
@ -168,14 +170,14 @@ class Resque_Tests_WorkerTest extends Resque_Tests_TestCase
public function testWorkerRecordsWhatItIsWorkingOn() public function testWorkerRecordsWhatItIsWorkingOn()
{ {
$worker = new Resque_Worker('jobs'); $worker = new \Resque\Worker('jobs');
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->registerWorker(); $worker->registerWorker();
$payload = [ $payload = [
'class' => 'Test_Job' 'class' => '\Resque\Test\TestJob'
]; ];
$job = new Resque_Job('jobs', $payload); $job = new \Resque\Job\Job('jobs', $payload);
$worker->workingOn($job); $worker->workingOn($job);
$job = $worker->job(); $job = $worker->job();
@ -188,14 +190,17 @@ class Resque_Tests_WorkerTest extends Resque_Tests_TestCase
public function testWorkerErasesItsStatsWhenShutdown() public function testWorkerErasesItsStatsWhenShutdown()
{ {
Resque::enqueue('jobs', 'Test_Job'); \Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob');
Resque::enqueue('jobs', 'Invalid_Job'); \Resque\Resque::enqueue('jobs', '\Resque\Test\InvalidJob');
$worker = new Resque_Worker('jobs'); $worker = new \Resque\Worker('jobs');
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->work(0); $worker->work(0);
$worker->work(0); $worker->work(0);
// Allow time for async unlink to work
sleep(2);
$this->assertEquals(0, $worker->getStat('processed')); $this->assertEquals(0, $worker->getStat('processed'));
$this->assertEquals(0, $worker->getStat('failed')); $this->assertEquals(0, $worker->getStat('failed'));
} }
@ -203,84 +208,84 @@ class Resque_Tests_WorkerTest extends Resque_Tests_TestCase
public function testWorkerCleansUpDeadWorkersOnStartup() public function testWorkerCleansUpDeadWorkersOnStartup()
{ {
// Register a good worker // Register a good worker
$goodWorker = new Resque_Worker('jobs'); $goodWorker = new \Resque\Worker('jobs');
$goodWorker->setLogger(new Resque_Log()); $goodWorker->setLogger(new \Resque\Log());
$goodWorker->registerWorker(); $goodWorker->registerWorker();
$workerId = explode(':', $goodWorker); $workerId = explode(':', $goodWorker);
// Register some bad workers // Register some bad workers
$worker = new Resque_Worker('jobs'); $worker = new \Resque\Worker('jobs');
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->setId($workerId[0] . ':1:jobs'); $worker->setId($workerId[0] . ':1:jobs');
$worker->registerWorker(); $worker->registerWorker();
$worker = new Resque_Worker(['high', 'low']); $worker = new \Resque\Worker(['high', 'low']);
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->setId($workerId[0] . ':2:high,low'); $worker->setId($workerId[0] . ':2:high,low');
$worker->registerWorker(); $worker->registerWorker();
$this->assertEquals(3, count(Resque_Worker::all())); $this->assertEquals(3, count(\Resque\Worker::all()));
$goodWorker->pruneDeadWorkers(); $goodWorker->pruneDeadWorkers();
// There should only be $goodWorker left now // There should only be $goodWorker left now
$this->assertEquals(1, count(Resque_Worker::all())); $this->assertEquals(1, count(\Resque\Worker::all()));
} }
public function testDeadWorkerCleanUpDoesNotCleanUnknownWorkers() public function testDeadWorkerCleanUpDoesNotCleanUnknownWorkers()
{ {
// Register a bad worker on this machine // Register a bad worker on this machine
$worker = new Resque_Worker('jobs'); $worker = new \Resque\Worker('jobs');
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$workerId = explode(':', $worker); $workerId = explode(':', $worker);
$worker->setId($workerId[0] . ':1:jobs'); $worker->setId($workerId[0] . ':1:jobs');
$worker->registerWorker(); $worker->registerWorker();
// Register some other false workers // Register some other false workers
$worker = new Resque_Worker('jobs'); $worker = new \Resque\Worker('jobs');
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->setId('my.other.host:1:jobs'); $worker->setId('my.other.host:1:jobs');
$worker->registerWorker(); $worker->registerWorker();
$this->assertEquals(2, count(Resque_Worker::all())); $this->assertEquals(2, count(\Resque\Worker::all()));
$worker->pruneDeadWorkers(); $worker->pruneDeadWorkers();
// my.other.host should be left // my.other.host should be left
$workers = Resque_Worker::all(); $workers = \Resque\Worker::all();
$this->assertEquals(1, count($workers)); $this->assertEquals(1, count($workers));
$this->assertEquals((string)$worker, (string)$workers[0]); $this->assertEquals((string)$worker, (string)$workers[0]);
} }
public function testWorkerFailsUncompletedJobsOnExit() public function testWorkerFailsUncompletedJobsOnExit()
{ {
$worker = new Resque_Worker('jobs'); $worker = new \Resque\Worker('jobs');
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->registerWorker(); $worker->registerWorker();
$payload = [ $payload = [
'class' => 'Test_Job' 'class' => '\Resque\Test\TestJob'
]; ];
$job = new Resque_Job('jobs', $payload); $job = new \Resque\Job\Job('jobs', $payload);
$worker->workingOn($job); $worker->workingOn($job);
$worker->unregisterWorker(); $worker->unregisterWorker();
$this->assertEquals(1, Resque_Stat::get('failed')); $this->assertEquals(1, \Resque\Stat::get('failed'));
} }
public function testBlockingListPop() public function testBlockingListPop()
{ {
$worker = new Resque_Worker('jobs'); $worker = new \Resque\Worker('jobs');
$worker->setLogger(new Resque_Log()); $worker->setLogger(new \Resque\Log());
$worker->registerWorker(); $worker->registerWorker();
Resque::enqueue('jobs', 'Test_Job_1'); \Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob_1');
Resque::enqueue('jobs', 'Test_Job_2'); \Resque\Resque::enqueue('jobs', '\Resque\Test\TestJob_2');
$i = 1; $i = 1;
while ($job = $worker->reserve(true, 2)) { while ($job = $worker->reserve(true, 2)) {
$this->assertEquals('Test_Job_' . $i, $job->payload['class']); $this->assertEquals('\Resque\Test\TestJob_' . $i, $job->payload['class']);
if ($i == 2) { if ($i == 2) {
break; break;

View file

@ -1,4 +1,7 @@
<?php <?php
namespace Resque\Test;
/** /**
* Resque test bootstrap file - sets up a test environment. * Resque test bootstrap file - sets up a test environment.
* *
@ -8,38 +11,33 @@
*/ */
$loader = require __DIR__ . '/../vendor/autoload.php'; $loader = require __DIR__ . '/../vendor/autoload.php';
$loader->add('Resque_Tests', __DIR__);
# Redis configuration # Redis configuration
global $redisTestServer; global $redisTestServer;
$redisTestServer = getenv("REDIS_SERVER") ?: "redis"; $redisTestServer = getenv("REDIS_SERVER") ?: "redis";
Resque::setBackend($redisTestServer); \Resque\Resque::setBackend($redisTestServer);
# Check Redis is accessable locally # Check Redis is accessable locally
try { try {
$redisTest = new Resque_Redis($redisTestServer); $redisTest = new \Resque\Redis($redisTestServer);
} catch (Exception $e) { } catch (\Exception $e) {
throw new Exception("Unable to connect to redis. Please check there is a redis-server running."); throw new \Exception("Unable to connect to redis. Please check there is a redis-server running.");
} }
$redisTest = null; $redisTest = null;
# Cleanup forked workers cleanly # Cleanup forked workers cleanly
if (function_exists('pcntl_signal')) { if (function_exists('pcntl_signal')) {
function sigint() pcntl_signal(SIGINT, function() { exit; });
{ pcntl_signal(SIGTERM, function() { exit; });
exit;
}
pcntl_signal(SIGINT, 'sigint');
pcntl_signal(SIGTERM, 'sigint');
} }
# Bootstrap it # Bootstrap it
class Test_Job class TestJob
{ {
public static $called = false; public static $called = false;
public $args = false;
public $queue;
public $job;
public function perform() public function perform()
{ {
@ -47,28 +45,33 @@ class Test_Job
} }
} }
class Failing_Job_Exception extends Exception class FailingJobException extends \Exception
{ {
} }
class Failing_Job class FailingJob
{
public function perform()
{
throw new Failing_Job_Exception('Message!');
}
}
class Test_Job_Without_Perform_Method
{
}
class Test_Job_With_SetUp
{ {
public static $called = false; public static $called = false;
public $args = false; public $args = false;
public $queue;
public $job;
public function perform()
{
throw new FailingJobException('Message!');
}
}
class TestJobWithoutPerformMethod
{
}
class TestJobWithSetUp
{
public static $called = false;
public $args = false;
public $queue;
public $job;
public function setUp() public function setUp()
{ {
@ -77,19 +80,19 @@ class Test_Job_With_SetUp
public function perform() public function perform()
{ {
} }
} }
class Test_Job_With_TearDown class TestJobWithTearDown
{ {
public static $called = false; public static $called = false;
public $args = false; public $args = false;
public $queue;
public $job;
public function perform() public function perform()
{ {
} }
public function tearDown() public function tearDown()