folk-plugin-jobs 0.3.2

Queue consumer plugin for Folk — pulls jobs from memory or Redis and dispatches to PHP workers
Documentation

folk-plugin-jobs

Queue consumer plugin for Folk — pulls jobs from memory or Redis and dispatches to PHP workers.

Configuration

Add to folk.build.toml:

[[plugin]]
crate_name = "folk-plugin-jobs"
version = "0.1"
config_key = "jobs"

Configure in folk.toml:

[jobs]
driver = "redis"                      # "memory" or "redis"
redis_url = "redis://127.0.0.1:6379"  # only for redis driver

[[jobs.queues]]
name = "default"
concurrency = 4
max_retries = 3

[[jobs.queues]]
name = "emails"
concurrency = 2
max_retries = 5

Settings

[jobs]

Key Type Default Description
driver "memory" | "redis" "memory" Queue backend. memory is in-process only (no persistence).
redis_url String "redis://127.0.0.1:6379" Redis connection URL (redis driver only).

[[jobs.queues]]

Key Type Default Description
name String "default" Queue name.
concurrency usize 4 Concurrent consumer tasks for this queue.
max_retries u32 3 Max retries before discarding a failed job.

RPC methods

Method Description
jobs.push Push a job to a queue. Params: {queue: string, payload: string|binary}
jobs.stats Returns queue depth for each configured queue.

Usage with folk-sdk (plain PHP)

Handler

<?php

use Folk\Sdk\Jobs\JobsModeHandler;

class MyJobHandler implements JobsModeHandler
{
    public function process(mixed $payload): mixed
    {
        // $payload is the raw string that was pushed to the queue.
        // Parse it however you want — JSON, msgpack, etc.
        $data = json_decode($payload, true);

        // Do work...
        file_put_contents('/tmp/job.log', $data['task'] . "\n", FILE_APPEND);

        return ['status' => 'ok'];
    }
}

Registration

<?php
// bin/folk-worker (or your entry point)

$loop = new \Folk\Sdk\Worker\WorkerLoop();
$loop->registerJobsHandler(new MyJobHandler());
$loop->run();

Pushing jobs

Jobs are pushed via the Folk admin RPC socket, not directly to Redis. Use the built-in RPC client:

<?php

use Folk\Sdk\Rpc\RpcClient;

$rpc = new RpcClient('./tmp/folk.sock');

$rpc->call('jobs.push', [
    'queue'   => 'default',
    'payload' => json_encode(['task' => 'send-email', 'to' => 'user@example.com']),
]);

This works with both memory and redis drivers — your code doesn't need to know which driver is used.

Usage with Laravel (folk-laravel)

Setup

  1. Set queue connection in .env:
QUEUE_CONNECTION=folk
  1. Add the folk connection to config/queue.php:
'folk' => [
    'driver' => 'folk',
    'queue' => 'default',
],
  1. Configure rpc_socket in config/folk.php:
return [
    'rpc_socket' => './tmp/folk.sock',
];

Dispatching jobs

Use standard Laravel dispatch — no changes needed:

// Simple dispatch
TestJob::dispatch($data);

// To a specific queue
TestJob::dispatch($data)->onQueue('emails');

Jobs flow through Folk transparently:

Laravel dispatch() --> FolkQueue --> RPC (jobs.push) --> folk-plugin-jobs --> [memory|redis] --> PHP worker --> fire()

Laravel serializes the job, Folk handles routing and storage. Your application code never touches Redis directly.

Job classes

Standard Laravel job classes work out of the box:

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;

class SendEmail implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable;

    public function __construct(
        public readonly string $to,
        public readonly string $subject,
    ) {}

    public function handle(): void
    {
        // Send the email...
    }
}

Multiple queues

Define queues in folk.toml and dispatch to them by name:

[[jobs.queues]]
name = "default"
concurrency = 4

[[jobs.queues]]
name = "emails"
concurrency = 2

[[jobs.queues]]
name = "reports"
concurrency = 1
SendEmail::dispatch($to, $subject)->onQueue('emails');
GenerateReport::dispatch($params)->onQueue('reports');

How it works

Drivers

Memory — In-process VecDeque. No persistence. Good for development and testing.

RedisBLPOP for consumption, RPUSH for enqueue. Each queue is a Redis list key. At-least-once semantics.

Consumer loop

For each queue, the plugin spawns concurrency consumer tasks:

  1. driver.pop(queue) — blocks until a job is available
  2. Sends payload to PHP worker via jobs.process RPC
  3. On failure, retries with exponential backoff (2s, 4s, 8s, ..., max 32s)
  4. After max_retries failures, job is discarded and logged

Push via RPC

The jobs.push RPC method accepts {queue, payload} and pushes to the configured driver. This is how FolkQueue (Laravel) and RpcClient (SDK) submit jobs without knowing the backend.

License

MIT