php-resque/README.md

511 lines
14 KiB
Markdown
Raw Permalink Normal View History

php-resque: PHP Background (Resque) Worker
2010-04-18 13:58:43 +00:00
===========================================
Resque is a Redis-backed library for creating background jobs, placing
those jobs on one or more queues, and processing them later.
2010-04-18 13:58:43 +00:00
2012-05-02 09:37:36 +00:00
## Background ##
2010-04-18 13:58:43 +00:00
2018-05-25 02:26:53 +00:00
Resque was developed by the folks at GitHub and written in Ruby.
What you're seeing here is an almost direct port of the Resque worker and enqueue system to PHP.
2010-04-18 13:58:43 +00:00
For more information on Resque, visit the official GitHub project:
<https://github.com/resque/resque>
2010-04-18 13:58:43 +00:00
2012-05-02 09:37:36 +00:00
For further information, see the launch post on the GitHub blog:
2010-04-18 13:58:43 +00:00
<http://github.com/blog/542-introducing-resque>
The PHP port does NOT include its own web interface for viewing queue
stats, as the data is stored in the exact same expected format as the
Ruby version of Resque.
2012-05-02 09:37:36 +00:00
The PHP port provides much the same features as the Ruby version:
2010-04-18 13:58:43 +00:00
* Workers can be distributed between multiple machines
* Includes support for priorities (queues)
* Resilient to memory leaks (forking)
2010-04-18 13:58:43 +00:00
* Expects failure
2012-05-02 09:37:36 +00:00
It also supports the following additional features:
2010-04-18 13:58:43 +00:00
* Has the ability to track the status of jobs
* Will mark a job as failed, if a forked child running a job does
not exit with a status code as 0
* Has built in support for `setUp` and `tearDown` methods, called
pre and post jobs
2010-04-18 13:58:43 +00:00
2019-06-02 10:21:42 +00:00
On top of the original fork (chrisboulton/php-resque) I have added:
* Custom log levels
* PHP7.0+ compatibility
2012-05-02 09:37:36 +00:00
## Requirements ##
2019-06-02 10:21:42 +00:00
* PHP 7.0+
* phpredis
2012-05-02 09:37:36 +00:00
* Redis 2.2+
## Getting Started ##
The easiest way to work with php-resque is when it's installed as a
Composer package inside your project.
If you're not familiar with Composer, please see <http://getcomposer.org/>.
1. Run `composer require idanoo/php-resque`.
2. If you haven't already, add the Composer autoload to your project's
initialization file. (example)
```sh
require 'vendor/autoload.php';
```
2010-04-18 13:58:43 +00:00
## Jobs ##
### Queueing Jobs ###
Jobs are queued as follows:
```php
// Required if redis is located elsewhere
Resque::setBackend('redis:6379');
2018-06-22 08:13:16 +00:00
$args = ['name' => 'TestName'];
Resque::enqueue('default', 'My_Job', $args);
```
2010-04-18 13:58:43 +00:00
### Defining Jobs ###
Each job should be in its own class, and include a `perform` method.
2010-04-18 13:58:43 +00:00
```php
class My_Job
{
public function perform()
{
2018-05-25 02:26:53 +00:00
echo $this->args['name']; // Outputs 'TestName'
}
}
```
When the job is run, the class will be instantiated and any arguments
will be set as an array on the instantiated object, and are accessible
via `$this->args`.
2010-04-18 13:58:43 +00:00
Any exception thrown by a job will result in the job failing - be
careful here and make sure you handle the exceptions that shouldn't
result in a job failing.
Jobs can also have `setUp` and `tearDown` methods. If a `setUp` method
is defined, it will be called before the `perform` method is run.
The `tearDown` method, if defined, will be called after the job finishes.
```php
class My_Job
{
public function setUp()
{
// ... Set up environment for this job
}
public function perform()
{
// .. Run job
}
public function tearDown()
{
// ... Remove environment for this job
}
}
```
2014-09-17 00:20:26 +00:00
### Dequeueing Jobs ###
This method can be used to conveniently remove a job from a queue.
```php
// Removes job class 'My_Job' of queue 'default'
2014-09-17 00:20:26 +00:00
Resque::dequeue('default', ['My_Job']);
// Removes job class 'My_Job' with Job ID '087df5819a790ac666c9608e2234b21e' of queue 'default'
2016-08-09 13:13:21 +00:00
Resque::dequeue('default', ['My_Job' => '087df5819a790ac666c9608e2234b21e']);
// Removes job class 'My_Job' with arguments of queue 'default'
2018-06-22 08:13:16 +00:00
Resque::dequeue('default', ['My_Job' => ['foo' => 1, 'bar' => 2]]);
// Removes multiple jobs
Resque::dequeue('default', ['My_Job', 'My_Job2']);
2014-09-17 00:20:26 +00:00
```
If no jobs are given, this method will dequeue all jobs matching the provided queue.
```php
// Removes all jobs of queue 'default'
Resque::dequeue('default');
```
2010-04-18 13:58:43 +00:00
### Tracking Job Statuses ###
php-resque has the ability to perform basic status tracking of a queued
job. The status information will allow you to check if a job is in the
queue, is currently being run, has finished, or has failed.
2010-04-18 13:58:43 +00:00
To track the status of a job, pass `true` as the fourth argument to
`Resque::enqueue`. A token used for tracking the job status will be
returned:
2013-07-18 07:57:53 +00:00
```php
$token = Resque::enqueue('default', 'My_Job', $args, true);
echo $token;
2013-07-18 07:57:53 +00:00
```
2010-04-18 13:58:43 +00:00
To fetch the status of a job:
2013-07-18 07:57:53 +00:00
```php
$status = new Resque_Job_Status($token);
echo $status->get(); // Outputs the status
2013-07-18 07:57:53 +00:00
```
2010-04-18 13:58:43 +00:00
Job statuses are defined as constants in the `Resque_Job_Status` class.
Valid statuses include:
2013-07-18 07:57:53 +00:00
* `Resque_Job_Status::STATUS_WAITING` - Job is still queued
* `Resque_Job_Status::STATUS_RUNNING` - Job is currently running
* `Resque_Job_Status::STATUS_FAILED` - Job has failed
* `Resque_Job_Status::STATUS_COMPLETE` - Job is complete
* `false` - Failed to fetch the status - is the token valid?
2010-04-18 13:58:43 +00:00
Statuses are available for up to 24 hours after a job has completed
or failed, and are then automatically expired. A status can also
forcefully be expired by calling the `stop()` method on a status
class.
## Workers ##
Workers work in the exact same way as the Ruby workers. For complete
documentation on workers, see the original documentation.
A basic "up-and-running" `bin/resque` file is included that sets up a
running worker environment. (`vendor/bin/resque` when installed
via Composer)
2010-04-18 13:58:43 +00:00
The exception to the similarities with the Ruby version of resque is
how a worker is initially setup. To work under all environments,
not having a single environment such as with Ruby, the PHP port makes
*no* assumptions about your setup.
To start a worker, it's very similar to the Ruby version:
```sh
$ QUEUE=file_serve php bin/resque
```
2010-04-18 13:58:43 +00:00
It's your responsibility to tell the worker which file to include to get
your application underway. You do so by setting the `APP_INCLUDE` environment
variable:
```sh
$ QUEUE=file_serve APP_INCLUDE=../application/init.php php bin/resque
```
*Pro tip: Using Composer? More than likely, you don't need to worry about
`APP_INCLUDE`, because hopefully Composer is responsible for autoloading
your application too!*
2010-04-18 13:58:43 +00:00
Getting your application underway also includes telling the worker your job
classes, by means of either an autoloader or including them.
Alternately, you can always `include('bin/resque')` from your application and
skip setting `APP_INCLUDE` altogether. Just be sure the various environment
variables are set (`setenv`) before you do.
2010-04-18 13:58:43 +00:00
### Logging ###
The port supports the same environment variables for logging to STDOUT.
Setting `LOGLEVEL` will print different logs depending on levels.
Valid loglevels are listed below with an example.
Default `LOGLEVEL` is `WARNING`.
2010-04-18 13:58:43 +00:00
```bash
[DEBUG/INFO/NOTICE/WARNING/ERROR/CRITICAL/ALERT/EMERGENCY]
```
```sh
$ LOGLEVEL=DEBUG QUEUE=file_serve bin/resque
```
2010-04-18 13:58:43 +00:00
### Priorities and Queue Lists ###
Similarly, priority and queue list functionality works exactly
the same as the Ruby workers. Multiple queues should be separated with
a comma, and the order that they're supplied in is the order that they're
checked in.
As per the original example:
```sh
$ QUEUE=file_serve,warm_cache bin/resque
```
2010-04-18 13:58:43 +00:00
The `file_serve` queue will always be checked for new jobs on each
iteration before the `warm_cache` queue is checked.
### Running All Queues ###
All queues are supported in the same manner and processed in alphabetical
order:
```sh
$ QUEUE='*' bin/resque
```
2010-04-18 13:58:43 +00:00
### Running Multiple Workers ###
Multiple workers can be launched simultaneously by supplying the `COUNT`
environment variable:
2010-04-18 13:58:43 +00:00
```sh
$ COUNT=5 bin/resque
```
2010-04-18 13:58:43 +00:00
Be aware, however, that each worker is its own fork, and the original process
will shut down as soon as it has spawned `COUNT` forks. If you need to keep
track of your workers using an external application such as `monit`, you'll
need to work around this limitation.
### Custom prefix ###
When you have multiple apps using the same Redis database it is better to
use a custom prefix to separate the Resque data:
```sh
$ PREFIX=my-app-name bin/resque
```
2010-04-18 13:58:43 +00:00
### Forking ###
Similarly to the Ruby versions, supported platforms will immediately
fork after picking up a job. The forked child will exit as soon as
the job finishes.
The difference with php-resque is that if a forked child does not
exit nicely (PHP error or such), php-resque will automatically fail
the job.
### Signals ###
Signals also work on supported platforms exactly as in the Ruby
version of Resque:
* `QUIT` - Wait for job to finish processing then exit
* `TERM` / `INT` - Immediately kill job then exit
* `USR1` - Immediately kill job but don't exit
2013-07-18 07:57:53 +00:00
* `USR2` - Pause worker, no new jobs will be processed
* `CONT` - Resume worker.
2010-04-18 13:58:43 +00:00
### Process Titles/Statuses ###
The Ruby version of Resque has a nifty feature whereby the process
title of the worker is updated to indicate what the worker is doing,
and any forked children also set their process title with the job
being run. This helps identify running processes on the server and
their resque status.
**PHP does not have this functionality by default until 5.5.**
2010-04-18 13:58:43 +00:00
A PECL module (<http://pecl.php.net/package/proctitle>) exists that
adds this functionality to PHP before 5.5, so if you'd like process
titles updated, install the PECL module as well. php-resque will
automatically detect and use it.
2011-03-27 07:42:46 +00:00
## Event/Hook System ##
php-resque has a basic event system that can be used by your application
to customize how some of the php-resque internals behave.
You listen in on events (as listed below) by registering with `Resque_Event`
and supplying a callback that you would like triggered when the event is
raised:
```sh
Resque_Event::listen('eventName', [callback]);
```
2011-03-27 07:42:46 +00:00
`[callback]` may be anything in PHP that is callable by `call_user_func_array`:
2013-07-18 07:57:53 +00:00
* A string with the name of a function
* An array containing an object and method to call
* An array containing an object and a static method to call
2018-06-22 08:13:16 +00:00
* A closure
2011-03-27 07:42:46 +00:00
Events may pass arguments (documented below), so your callback should accept
these arguments.
You can stop listening to an event by calling `Resque_Event::stopListening`
with the same arguments supplied to `Resque_Event::listen`.
It is up to your application to register event listeners. When enqueuing events
in your application, it should be as easy as making sure php-resque is loaded
and calling `Resque_Event::listen`.
When running workers, if you run workers via the default `bin/resque` script,
2011-03-27 07:42:46 +00:00
your `APP_INCLUDE` script should initialize and register any listeners required
for operation. If you have rolled your own worker manager, then it is again your
responsibility to register listeners.
### Events ###
#### beforeFirstFork ####
Called once, as a worker initializes. Argument passed is the instance of `Resque_Worker`
that was just initialized.
#### beforeFork ####
Called before php-resque forks to run a job. Argument passed contains the instance of
`Resque_Job` for the job about to be run.
`beforeFork` is triggered in the **parent** process. Any changes made will be permanent
for as long as the **worker** lives.
2011-03-27 07:42:46 +00:00
#### afterFork ####
Called after php-resque forks to run a job (but before the job is run). Argument
passed contains the instance of `Resque_Job` for the job about to be run.
`afterFork` is triggered in the **child** process after forking out to complete a job. Any
changes made will only live as long as the **job** is being processed.
2011-03-27 07:42:46 +00:00
#### beforePerform ####
Called before the `setUp` and `perform` methods on a job are run. Argument passed
contains the instance of `Resque_Job` for the job about to be run.
2011-03-27 07:42:46 +00:00
You can prevent execution of the job by throwing an exception of `Resque_Job_DontPerform`.
Any other exceptions thrown will be treated as if they were thrown in a job, causing the
job to fail.
#### afterPerform ####
Called after the `perform` and `tearDown` methods on a job are run. Argument passed
contains the instance of `Resque_Job` that was just run.
Any exceptions thrown will be treated as if they were thrown in a job, causing the job
to be marked as having failed.
#### onFailure ####
Called whenever a job fails. Arguments passed (in this order) include:
* Exception - The exception that was thrown when the job failed
* Resque_Job - The job that failed
#### beforeEnqueue ####
Called immediately before a job is enqueued using the `Resque::enqueue` method.
Arguments passed (in this order) include:
* Class - string containing the name of the job to be enqueued
* Arguments - array of arguments for the job
* Queue - string containing the name of the queue the job is to be enqueued in
* ID - string containing the token of the job to be enqueued
You can prevent enqueing of the job by throwing an exception of `Resque_Job_DontCreate`.
2011-03-27 07:42:46 +00:00
#### afterEnqueue ####
Called after a job has been queued using the `Resque::enqueue` method. Arguments passed
(in this order) include:
* Class - string containing the name of scheduled job
2011-03-27 07:42:46 +00:00
* Arguments - array of arguments supplied to the job
* Queue - string containing the name of the queue the job was added to
* ID - string containing the new token of the enqueued job
## Supervisor Configuration ##
You may like to run php-resque on a supervisor task to manage the processes.
The following is a default config that can be modified to suit.
```sh
[program:resque-dev]
directory=/var/www # Project root
command=php vendor/bin/resque
numprocs=2 # Change this value for more threads
environment=LOGLEVEL=NOTICE,QUEUE='*',BLOCKING=1,COUNT=1,APP_INCLUDE='includes/autoload.php',REDIS_BACKEND=127.0.0.1,REDIS_BACKEND_DB=0
redirect_stderr=true # Output stderr to logfile
stdout_logfile=/var/log/resque.log
autostart=true
autorestart=true
stopsignal=QUIT
process_name = %(program_name)s_%(process_num)02d
```
Issues:
- Restarting worker doesn't always make it use updated code, I find on a dev-environment issuing
the following command works well to restart everything.
`sudo /etc/init.d/supervisor force-stop && sleep 1 && sudo /etc/init.d/supervisor restart`
## Step-By-Step ##
For a more in-depth look at what php-resque does under the hood (without
needing to directly examine the code), have a look at `HOWITWORKS.md`.
2011-03-27 07:42:46 +00:00
## Contributors ##
### Current Maintainers ###
* @idanoo
### Past Maintainer / Forked From ###
* @chrisboulton
### Others ###
* @acinader
* @ajbonner
* @andrewjshults
* @atorres757
* @benjisg
* @cballou
* @chaitanyakuber
* @charly22
* @CyrilMazur
* @d11wtq
* @danhunsaker
* @dceballos
* @ebernhardson
* @hlegius
* @hobodave
* @humancopy
2014-06-26 09:19:04 +00:00
* @iskandar
* @JesseObrien
* @jjfrey
* @jmathai
* @joshhawthorne
* @KevBurnsJr
* @lboynton
* @maetl
* @matteosister
* @MattHeath
* @mickhrmweb
* @Olden
* @patrickbajao
* @pedroarnal
* @ptrofimov
* @rajibahmed
* @richardkmiller
* @Rockstar04
* @ruudk
* @salimane
* @scragg0x
* @scraton
* @thedotedge
* @tonypiper
* @trimbletodd
* @warezthebeef