Download the PHP package italix/jobs without Composer
On this page you can find all versions of the php package italix/jobs. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Package jobs
Short Description Database-backed queue and cron scheduling: JSON payloads not serialized objects, atomic claiming, backoff, stalled-worker recovery
License MPL-2.0
Homepage https://github.com/italix-net/jobs
Informations about the package jobs
Italix Jobs
A database-backed queue and cron scheduling. Work is described now and run later, by a worker that cannot run it twice and does not lose it when it dies.
One dependency: psr/container, which is interface-only.
Writing a job
Ids in the payload, not objects. A payload carrying a whole record is stale by the time it runs.
name_code() is not the class name. It is what jobs:status groups by and what jobs:retry --name= matches, so renaming a class must not break either.
Why payload()/from_payload() and not serialize()
Two reasons, and the second is the serious one.
A serialized object carries its private properties by name. Rename one, or add a constructor argument, and every row already queued becomes unrestorable — silently, at 3am, for work somebody is waiting on.
And unserialize() on a value read back from a table instantiates whatever class the string names
and runs its magic methods. Any path that can write to that table becomes remote code execution. A
JSON payload plus an explicit factory can only ever produce the class the code asked for.
Running
One crontab entry drives everything:
jobs:work does one pass and exits — supervision belongs to cron or systemd, and a PHP process
that runs for days accumulates every leak its dependencies have.
Watch jobs:status, not jobs:work. The worker exiting 0 only means the worker ran; a failed
job is reported by jobs:status, which exits 1 when anything is in failed.
What happens when a job fails
| throws | error_c = threw, attempt counted, requeued after backoff |
| throws again, attempts exhausted | state failed, stays until somebody looks |
| class missing or payload rejected | error_c = unrestorable, failed immediately — retrying cannot help |
| worker dies mid-job | reclaimed after the visibility timeout, error_c = stalled |
Backoff doubles: 30s, 60s, 120s. A mail server that is down stays down for a while, and retrying it every second turns one outage into a thousand log lines.
Nothing is ever dropped. A job that stops existing is the queue equivalent of a validation rule that silently passes.
Scheduling
Declared in configuration, like routes and commands:
ix jobs:schedule --list prints them, which is only possible because there is a list.
Running the cron twice enqueues once. due() returns a deduplication key naming the job and the
minute, and the store's unique index turns the second push into a no-op. The system crontab is not
a precision instrument: a minute can fire twice, a catch-up run can replay, two hosts can both be
scheduled. Nothing anywhere has to be careful.
That is also why the resolution is a minute and not a second — the key has to be stable across the whole window in which the cron might fire.
Cron syntax: five fields, with *, n, a-b, a,b,c and a step suffix on any of those. 0 and
7 both mean Sunday, because both spellings are in circulation.
Concurrency, in one paragraph
claim() selects a candidate and then updates it conditionally on it still being pending. If
another worker got there first the update affects zero rows and this one looks again. No
SELECT … FOR UPDATE, no transaction held open across the work — just an update that can only
succeed once. That is why claiming is a method on JobStore rather than a sequence the caller
assembles: a store that cannot do it atomically is a store that runs jobs twice.
Deliberately not
- No Redis or SQS driver in core.
JobStoreis the seam; an out-of-tree implementation costs nothing to core. - No batching, chaining, or unique-job locks. The deduplication key covers the case that actually recurs.
- No
@daily, no seconds field, noL/W/#. Little code, large surprise. - No long-lived worker process.