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

Php Resque Ex Laravel Package

kamisama/php-resque-ex

Redis-backed background job processing for PHP. Enqueue jobs and run workers to process them asynchronously, with queue management, logging, and failure handling. An enhanced fork of php-resque with extra features and fixes for production use.

Deep Wiki
Context7

Getting Started

kamisama/php-resque-ex is a maintained-fork-lineage port of the Ruby Resque background job system. It is not a Laravel queue driver — there is no ShouldQueue, no auto-discovery, and jobs do not run inside Laravel's lifecycle unless you bootstrap the framework yourself. The minimum viable setup is three pieces: a backend connection, an enqueue call, and a worker process.

1. Install and configure the Redis backend. Put this in a service provider (or a dedicated ResqueServiceProvider):

// composer.json: "kamisama/php-resque-ex": "^1.2"
use Resque;

public function boot()
{
    Resque::setBackend(
        config('database.redis.default.host') . ':' . config('database.redis.default.port'),
        (int) config('database.redis.default.database')
    );
    if ($password = config('database.redis.default.password')) {
        Resque::redis()->auth($password);
    }
}

If the phpredis extension is installed, it is used automatically (much faster than the bundled pure-PHP Redisent client). Otherwise you get the slower fallback — acceptable for low volume, but verify which client is in use before benchmarking.

2. Create a job class. Any class with a public perform() method works. $this->args holds the payload:

class SendWelcomeEmail
{
    public function perform()
    {
        $user = User::find($this->args['userId']); // needs Laravel booted — see Gotchas
        Mail::to($user->email)->send(new WelcomeMail($user));
    }
}

3. Enqueue from normal Laravel code:

Resque::enqueue('default', SendWelcomeEmail::class, ['userId' => $user->id]);

4. Run a worker (under supervisor, systemd, or a container sidecar):

QUEUE=default INTERVAL=5 php vendor/bin/resque

Where to look first: Resque::enqueue() and the bin/resque executable are the entire public surface you will touch daily. The Resque_Job_Status and Resque_Stat classes are the secondary API for observability. Read the job class perform() convention once and the rest is Redis conventions.

First use case: offloading slow mailers, third-party API calls, PDF generation, or image resizing from the HTTP request. It is a workhorse for deferring anything that shouldn't block a response and doesn't need complex retry/backoff semantics.

Implementation Patterns

A bootstrapped base job. Jobs execute in the worker process, which does not share Laravel's container. The cleanest pattern is a custom worker entry point that boots the framework once, so perform() can use facades and the container normally:

// bin/resque-laravel
require __DIR__ . '/../vendor/autoload.php';
$app = require_once __DIR__ . '/../bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();

$queues = explode(',', getenv('QUEUE') ?: 'default');
$worker = new Resque_Worker($queues);
$worker->work((int) (getenv('INTERVAL') ?: 5));

This is the single most important integration decision — do it up front or every job will silently fail on the first app()/Mail::/DB:: call.

Queue prioritization. Pass a comma-separated list and Resque polls them in order — the leftmost is highest priority:

QUEUE=critical,high,default,low php bin/resque

QUEUE=* processes every queue, but priority order becomes Redis-set dependent. Prefer explicit lists.

Job status tracking. Off by default; enable per dispatch and persist the token yourself (Redis is volatile):

$token = Resque::enqueue('default', ReportJob::class, [$id], true);

// later
$status = (new Resque_Job_Status($token))->get();
// Resque_Job_Status::STATUS_QUEUED | RUNNING | COMPLETE | FAILED

Store $token on a model or in cache to poll from the UI. Note that completed-status records expire (Resque_Job_Status uses a TTL), so don't treat them as a permanent audit log.

Multiple worker processes. Use supervisor (a dozen workers on the same host is typical), each with its own QUEUE if you want isolation. INTERVAL controls Redis polling frequency — the default of 5 seconds is fine; lowering it increases idle load, raising it increases latency.

Failure handling and retries. Resque has a configurable failure backend (Resque_Failure_Redis by default, exposed via the failed queue). There is no built-in retry. The idiomatic pattern is to catch inside perform() and re-enqueue with a counter arg:

public function perform()
{
    try {
        $this->handle();
    } catch (\Throwable $e) {
        $attempt = ($this->args['attempt'] ?? 0) + 1;
        if ($attempt < 3) {
            Resque::enqueue($this->queue, static::class, array_merge($this->args, ['attempt' => $attempt]));
        } else {
            throw $e; // let Resque record the failure
        }
    }
}

Logging. This fork improves on upstream logging: env vars LOGGING, LOGLEVEL, LOG control worker logs, and jobs can write through Monolog if you wire it in the worker script. In a container it's usually cleaner to log to stderr and let the platform aggregate.

Testing. Static Resque::enqueue is hard to mock. The pragmatic approach is to point Resque::setBackend at a test Redis database in phpunit.xml and assert against raw Redis keys:

$this->assertSame(1, Resque::size('default'));

Then pop the payload with Resque::redis()->lpop('queue:default') and json_decode it to verify the class and args.

Gotchas and Tips

  • The package is archived. No security patches, no PHP 8.x guarantees. Pin a known-good version, run the CI against your target PHP minor, and treat migration to Laravel's native Redis queue (or Horizon) as a planned task, not an emergency. If you need an active fork with the same API, bzirost/php-resque or a private fork is the fallback.
  • Jobs run outside Laravel. Without a bootstrapped worker (see above), app(), facades, Eloquent, and config all fail — usually with a confusing "class not found" or "container not set" error rather than a clear bootstrap warning. Always run your worker via a custom entry point, not raw vendor/bin/resque, in a Laravel app.
  • Argument shape matters. $this->args is a single array passed verbatim through JSON. No named arguments, no typed value objects, no serialization magic. Keep args scalar and flat; put large payloads in a DB row and pass the ID.
  • The class name is a string. Resque::enqueue('default', MyJob::class, $args) resolves MyJob through the worker's autoloader at runtime. If the class is renamed or moved, the enqueue succeeds and the job fails silently at the worker — so add an assertion or a class_exists check on the enqueue side if you refactor often.
  • No automatic retries, no backoff, no dead-letter UI. The failed queue is your dead letter and it's just a Redis list. Budget for a small admin tool if reliability matters.
  • Signals are how you manage workers. QUIT is graceful (finishes the current job), TERM/INT are immediate, USR1 pauses, USR2 resumes. Laravel's queue:restart convention doesn't exist here — you send kill -QUIT <pid> from your deploy script or supervisor. Killing with TERM will corrupt in-flight jobs.
  • Redis key namespace collisions. Keys are prefixed resque: (resque:queue:default, resque:worker:*, resque:stat:*, resque:failed). If you share Redis with another app using resque: prefixes, workers will steal each other's jobs. Isolate via a separate database index or a key-prefix convention enforced at the client.
  • phpredis vs pure PHP. The extension is detected at runtime. This matters because the two clients have subtly different behavior on auth/select; if auth seems to work in one place but the worker can't connect, check which client loaded. Pure-PHP is roughly an order of magnitude slower per job dequeue.
  • INTERVAL is in seconds, and workers block nothing else. A single-threaded worker processes one job at a time. Concurrency = process count. Plan the supervisor config accordingly, and remember each worker holds its own Redis connection.
  • Status TTL bites status UIs. Resque_Job_Status records expire; poll status quickly or move completion to your own storage. Failed statuses linger differently from completed ones.
  • Extension points if you need them: Resque_Failure_Interface for custom failure backends (e.g., reporting to Sentry/Bugsnag), Resque_Log subclasses for log routing, and $worker->registerSigHandlers() if you're embedding workers inside another process. Resque::redis() gives you the raw client — useful for health checks (ping) but bypasses library abstractions.
  • No PHP 8.1+ enum/readonly awareness in the API. Job args are plain arrays; if your perform() uses constructor promotion or enums in signatures, they won't survive the JSON round-trip. Keep the entry point to perform() and plain data.
  • If you are evaluating this against Laravel's native queue: native Redis queue + Horizon gives you a driver, retries with exponential backoff, middleware, batching, job events, and a dashboard. If none of those are required and you specifically want Resque's cross-language queue compatibility (interop with Ruby/Python/Node Resque workers on the same Redis), php-resque-ex remains one of the few sane PHP options — otherwise it's a harder sell than it was a decade ago.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
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
cgv/localized-resource