NAME

Punk::Queue::Backend - the storage contract, and the shared implementation

SYNOPSIS

package My::Backend;
use parent 'Punk::Queue::Backend';   # optional

sub dequeue { ... }                  # the parts you do differently

DESCRIPTION

A backend is any class implementing the contract below. There is no base class you must inherit and no registry to enter: Punk::Queue->new(dsn => ..., backend => '+My::Backend') is the whole integration.

What inheriting from this class buys you is every shared method for free - enqueue, the terminal transitions, the migration runner, the clock probe - implemented in C, leaving only the genuinely divergent parts to write.

THE CONTRACT

Twelve required methods. A class answering to these is a working backend.

new(\%opts)                            -> $backend
dbh                                    -> $dbh
migrate($to?)                          -> $version
enqueue($task, \@args, \%opts)         -> $id
dequeue($worker_id, $timeout, \%opts)  -> \%job | undef
finish_job($id, $retries, $result)     -> 0|1
fail_job($id, $retries, $err)          -> 0|1
retry_job($id, $retries, \%opts)       -> 0|1
remove_job($id)                        -> 0|1
job_info($id)                          -> \%info | undef
register_worker($id?, \%opts)          -> $worker_id
stats()                                -> \%stats

Optional groups are probed with can and defaulted where a portable default exists: listing (list_jobs, list_workers, list_locks, history, note), the worker registry (unregister_worker, broadcast, receive), locks (lock, unlock, renew_lock), cron (upsert_cron, disable_missing_crons, due_crons, advance_cron), the job log (log_job, job_log) and housekeeping (repair, reset, notify).

Two signature details are load-bearing.

dequeue's $timeout is "how long you may wait", and the backend owns how it waits. That is what lets PostgreSQL block on LISTEN and SQLite poll with a jittered backoff behind one signature, without the caller knowing which it got.

finish_job, fail_job and retry_job take $retries and use it as an optimistic guard. Repair requeues a vanished worker's job by bumping the retry count, and without the guard that worker - which may still be alive and about to report success - would clobber the new attempt.

METHODS

dbh

The pooled database handle for this backend's dsn, connected on first use in this process.

migrate / schema_version / latest_version

The version the database is at, and the version this build knows how to apply. latest_version above schema_version means a migration is pending.

now / clock_delta

now is the current time in the database's frame of reference: this host's clock plus a delta probed once per connection.

Every timestamp this distribution binds comes from now, never from the local clock directly. Two hosts a minute apart is enough to claim a delayed job early, and "the job ran an hour before its delay" is a baffling symptom to debug from the inside.

has_returning

Whether the connection supports RETURNING - PostgreSQL always, SQLite from 3.35. When it does, an insert reads back its own id without a second round trip.

enqueue / job_info / finish_job / fail_job / retry_job / remove_job

list_jobs / list_workers / stats / reset

As documented in Punk::Queue, which delegates to them.

register_worker

my $id = $backend->register_worker(0, { role => 'child',
                                        queues => \@queues });
$backend->register_worker($id);      # refresh, keeping the id

One row per claiming process. A refresh whose row has been swept (by repair) falls through to a fresh registration rather than failing.

unregister_worker

$backend->unregister_worker($id);

worker_heartbeat

$backend->worker_heartbeat($id, \%status);

Prove the worker is alive; %status is stored as JSON for the admin UI, and undef keeps whatever is there. From phase 6 this is also where the broadcast inbox is drained.

SEE ALSO

Punk::Queue, Punk::Queue::Backend::SQLite.

AUTHOR

LNATION <email@lnation.org>

LICENSE AND COPYRIGHT

This software is Copyright (c) 2026 by LNATION <email@lnation.org>.

This is free software, licensed under:

The Artistic License 2.0 (GPL Compatible)