Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Resque Laravel Package

php-resque/resque

PHP-Resque is a Redis-backed background job queue for PHP inspired by Ruby's Resque. Enqueue jobs, run worker processes, and manage queues through a lightweight API for reliable asynchronous processing.

View on GitHub
Deep Wiki
Context7

Getting Started

Check the runtime first. This package needs the phpredis extension to talk to Redis and pcntl to fork workers:

php -m | grep -E '^(redis|pcntl)$'
php -v   # the codebase is 5.3-era; verify it runs on your PHP line

The repo is archived, so pin a commit (or a maintained fork such as mjphaynes/php-resque) rather than relying on a floating version constraint. If you are not interoperating with Ruby Resque or an existing Redis job format, stop here and use Laravel's native Redis queue instead — you get retries, backoff, timeouts and Horizon for free.

Three files to write: a bootstrap, a job, a call site.

// resque-bootstrap.php — referenced by APP_INCLUDE, loaded by web AND worker
require __DIR__ . '/vendor/autoload.php';

Resque::setBackend('127.0.0.1:6379', 1); // host:port, then Redis database
// app/Jobs/GenerateThumbnail.php
class GenerateThumbnail
{
    public $args;  // php-resque injects ->args ...
    public $job;   // ... and ->job onto the instance

    public function perform()
    {
        $path = $this->args['path'];
        // do the work; throw an exception to mark the job failed
    }
}
require __DIR__ . '/resque-bootstrap.php';

$token = Resque::enqueue('media', 'GenerateThumbnail', ['path' => $path], true);

Start a worker (exact command syntax varies by fork — run php bin/resque with no arguments to list commands):

QUEUE=media APP_INCLUDE=./resque-bootstrap.php VERBOSE=1 php bin/resque worker:start

Where to look when it misbehaves: bin/resque (all the environment variables: QUEUE, APP_INCLUDE, COUNT, INTERVAL, BLOCKING, PREFIX, LOGGING, LOGFILE, VERBOSE), lib/Resque.php (setBackend, enqueue, redis), lib/Resque/Worker.php (the fork loop, signal handling), lib/Resque/Job.php (payload decoding and the perform() invocation), and lib/Resque/Job/Status.php (status tokens).

First use case: replace an inline "send email / resize image / call webhook" call in a controller with enqueue, then verify LLEN resque:queue:media grows in Redis before starting a worker.

Implementation Patterns

Two bootstraps, one shared include. The web process only needs setBackend + enqueue; the worker needs your full framework booted. Put the framework bootstrap in a single APP_INCLUDE file so both paths agree on Redis host, database and key prefix:

// resque-bootstrap.php (used by APP_INCLUDE)
require __DIR__.'/vendor/autoload.php';

$app = require __DIR__.'/bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();

Resque::setBackend(config('database.redis.default.host').':'.config('database.redis.default.port'), 1);

Resolve dependencies inside perform(), not in the bootstrap. The worker forks a child per job; anything you connected or cached in the parent is inherited and unsafe in the child. A thin bridge job keeps the Laravel wiring out of every handler:

class RunHandler
{
    public $args;
    public $job;

    public function perform()
    {
        app($this->args['handler'])->handle($this->args['payload']);
    }
}

Lifecycle hooks. Jobs may also define setUp() (runs before perform) and tearDown() (runs after, even on failure) — use tearDown to release locks or flush per-job state.

Enqueue after the transaction commits. enqueue does an RPUSH immediately; if the surrounding DB transaction rolls back you have a job for a row that never existed. In Laravel, dispatch from DB::afterCommit() or a terminating callback.

Status tracking is opt-in and per-job. Pass true as the fourth argument to get a token back, store it on your model, then poll:

$token = Resque::enqueue('media', 'GenerateThumbnail', $args, true);
$status = new Resque_Job_Status($token);
$status->get(); // STATUS_WAITING / STATUS_RUNNING / STATUS_FAILED / STATUS_COMPLETE

Queue priority is positional. A worker watching QUEUE=high,default pops high first every iteration; QUEUE=* watches everything and checks queues in Redis set order. There is no weighting — model priority with more workers on the high queue.

Run workers under a process manager, not nohup. stopsignal=QUIT is important: QUIT lets the current child finish, TERM/INT kill it mid-job.

[program:resque]
command=php /var/www/app/bin/resque worker:start
environment=QUEUE="high,default",APP_INCLUDE="/var/www/app/resque-bootstrap.php",COUNT="1000",LOGGING="1",LOGFILE="/var/log/resque.log"
numprocs=4
process_name=%(program_name)s_%(process_num)02d
autostart=true
autorestart=true
stopsignal=QUIT

COUNT makes the worker exit after N jobs, letting the manager recycle it — useful for taming slow leaks.

Testing. Point tests at a dedicated database and call perform() directly for unit tests; only exercise the queue for integration cases:

Resque::setBackend('127.0.0.1:6379', 15);

$job = new GenerateThumbnail();
$job->args = ['path' => $fixture];
$job->perform();          // unit-level

Interop is the real reason to use it. The payload ({"class":..., "args":...}) is stored in Ruby-Resque-compatible keys, so a Laravel app can enqueue and a Ruby worker consume it (or vice versa). If you're migrating off it, a single Laravel job class that shells out to Resque::enqueue lets you drain the old system gradually.

Gotchas and Tips

  • Archived code + modern PHP. Undeclared properties ($this->args, $this->job) trigger deprecations on PHP 8.2+; declare them in your job classes. phpredis 6 also tightened argument types, so smoke-test every command path before upgrading PHP.
  • Redis eviction silently eats jobs. Queue keys live under a fixed resque: prefix. Use a dedicated database/instance with maxmemory-policy noeviction; an allkeys-lru policy will happily delete queued work.
  • Workers cache your code. The parent forks children, so a deploy leaves stale classes running until you restart workers. Always restart workers as part of deploy; opcache makes this worse if you forget.
  • Connections are inherited across fork(). Open PDO/Redis/cURL handles in APP_INCLUDE and both parent and children share sockets — that produces interleaved protocol errors that look like random failures. Connect lazily inside perform() and close in tearDown().
  • No pcntl means no isolation. On Windows or hosts without the extension, the worker runs jobs in-process: a fatal error kills the worker, and memory grows across jobs. Treat it as a development-only mode.
  • Arguments are JSON. No objects, resources or closures. Associative arrays survive as arrays; objects come back as arrays with the type erased.
  • Exceptions are the failure contract. Anything thrown lands in the failed set, with payload, exception, backtrace, worker and queue. Swallowing an exception means a failed job that reports success; rethrow after logging.
  • No retries, backoff, delayed jobs, timeouts or uniqueness. queue:retry ID re-enqueues the original payload immediately. Make perform() idempotent, and add a scheduler package (or a cron job) if you need delays.
  • A hung job blocks that worker forever. There is no job timeout — a single worker with stuck jobs means the whole queue stalls. Watch for long-running children and kill them via the signal, not by killing the parent.
  • Status tokens and the failed set never expire. Tracking adds Redis writes per job and leaves resque:job:<token>:status keys around; failure entries accumulate until you clear them. Monitor SCARD resque:failed and prune deliberately.
  • BLOCKING=1 changes the connection semantics. It uses Redis blocking pops for lower latency, requires phpredis and a connection you don't share, and drops the polling INTERVAL (default 5s) latency. Without it, expect up to INTERVAL seconds of pickup delay.
  • Graceful shutdown is your responsibility. QUIT finishes the current job; TERM interrupts it. If your process manager sends TERM by default, half-finished jobs will be retried or lost depending on your code.
  • Stale PIDs accumulate. Crashed or kill -9'd workers stay in the resque:workers set; worker:list will show ghosts until you clean the set.
  • Single Redis connection, no Cluster. Keys are manipulated with plain RPUSH/LPOP on one connection; don't point it at a Redis Cluster endpoint.
  • Extension points worth knowing: a custom failure backend (to route failures to Sentry/a table), subclassing Resque_Worker to override the fork/loop behaviour, and Resque::redis() for direct inspection of queues and failure data during debugging.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect