Search by

trail / queue

dodgycoffee

A light queue addon for trail

Package info

source.tube/brindly/trail-queue

Issues

Type:trail-addon

pkg:composer/trail/queue

Statistics

Installs: 0

Dependents: 0

Suggesters: 1

dev-main / 0.1.x-dev 2026-10-01 03:13 UTC

This package is auto-updated.

Last update: 2026-10-01 03:13:11 UTC


README

A light queue addon for trail

install

composer require trail/queue
trail/trail db::migrate

Needs trail/db

a job

Constructor args get stored as json. handle() gets services like pages do

use Trail\Queue\Jobs\Job;

final readonly class SendWelcome implements Job
{
    public function __construct(public int $userId) {}

    public function handle(Users $users, Outbox $outbox): void
    {
        ...
    }
}
  • args are plain json. strings, numbers, bools, null, arrays
  • objects throw LogicException when pushed

push one

use Trail\Queue\Backlog\Backlog;

public function __construct(private Backlog $backlog) {}

$this->backlog->push(new SendWelcome($user->id));
$this->backlog->push(new SendWelcome($user->id), delay: 3600);   // seconds

run a worker

trail/trail queue::work                 # loops. stops after an hour
trail/trail queue::work --for=600       # stops after 10 minutes
trail/trail queue::work --until-empty   # runs everything and stops

A queue runner is a good idea for background tasks. 2 good ways to do that:

  • process manager (systemd, supervisor, whatever) running queue::work that retarts when it exits
  • cron every minute running queue::work --until-empty

Cheeky supervisor example

[program:imma-queue]
command=/usr/bin/php /var/www/example.com/trail/trail queue::work
user=www-data
autostart=true
autorestart=true
stopwaitsecs=60
redirect_stderr=true
stdout_logfile=/var/log/imma-queue.log
  • autorestart restarts it after hourly exits
  • stopwaitsecs is how long it'll wait for a job to finish before stopping. Otherwise its killed and picked up again after timeout
  • restart after a deployment (supervisorctl restart imma-queue) to get new code

named queues

jobs are default unless someone gives it a real name

final readonly class BuildExport implements Job
{
    public const string QUEUE = 'slow';
    ...
}
trail/trail queue::work                        # every job starting with oldest
trail/trail queue::work --queue=mail,default   # mail then default
trail/trail queue::work --queue=slow           # worker just for slow stuff
  • trail/mail jobs go on mail
  • no --queue arg runs everything

when jobs fail

  • thrown job gets retried after backoff × attempt seconds (60, 120, ...)
  • after tries it gets marked as failed with error + log
  • stuck jobs because worker died get picked up again after timeout
  • jobs that keep killing the worker are marked failed
  • jobs can run more than once
trail/trail queue::failed        # list them
trail/trail queue::retry 12      # try it again
trail/trail queue::retry all
trail/trail queue::prune         # delete failed ones

jobs can set their own values. otherwise config tells it what to do

final readonly class PingWebhook implements Job
{
    public const int TRIES = 10;
    public const int BACKOFF = 600;   // 10m, 20m, 30m, ...
}

final readonly class ChargeCard implements Job
{
    // never twice
    public const int TRIES = 1;
}

schedule

cli commands / jobs running on a timer. worker checks once a minute

'queue' => [
    'schedule' => [
        'sessions::prune' => 'daily',
        'auth::prune' => 'daily',
        'queue::prune' => 'weekly',
        SendDigest::class => '0 8 * * 1',   // mondays 8am
    ],
],
  • hourly, daily, weekly, monthly, or cron (*, 1-5, 0,30, */15)
  • server timezone
  • commands get queued and run by worker
  • job classes cant take args
  • runs once per slot
  • missed runs over last hour play catch up

no worker?!

You can set it to just run right away during a request

'queue' => [
    'runNow' => true,
],

all the config stuff

'queue' => [
    'runNow' => false,

    // before fail
    'tries' => 3,

    // seconds. times the attempt
    'backoff' => 60,

    // seconds before stuck job is taken
    'timeout' => 900,

    // seconds queue::prune keeps failed jobs
    'keepFailed' => 604800,

    // `what => when`
    'schedule' => [],
],

do your own

Bind anything that implements Backlog in a site addon

$box->bind(Backlog::class, MyBacklog::class);