Migration to v3¶
v3.0 is a major, breaking release. It collapses the previously coexisting architectures into a
single clean design. The legacy mutable Job builder, the V1 Scheduler, the performance loggers,
the email notification service, and the old CLI commands have been removed. This guide maps the
old surface to its v3 replacement.
If you are coming from a
v2.0.0-alphabuild, the opt-inDaycry\Jobs\V2\namespace (JobDefinition,JobLease,QueueBackend,LegacyWorkerAdapter,TypedJobHandler) has been promoted to the root namespace and is now the only architecture.LegacyWorkerAdapteris gone — every backend implementsQueueBackendnatively.
What was removed¶
Removed |
Replacement |
|---|---|
Mutable |
|
V1 |
|
Handlers extending |
Handlers implementing |
|
Single |
|
|
Performance loggers ( |
Removed. Use the metrics collector ( |
|
Removed. Send notifications from your handler or a downstream job. |
|
Removed from the runtime. The history table ( |
|
One attempt in |
Callbacks/chaining ( |
Removed. Compose work explicitly (e.g. dispatch a follow-up job from a handler). |
|
Removed. |
CLI: |
|
API mapping¶
Defining and dispatching a job¶
Old (v1):
use Daycry\Jobs\Job;
$job = (new Job('command', 'app:report'))
->named('daily-report')
->dailyAt('02:00')
->maxRetries(3)
->enqueue('reports');
v3:
use Daycry\Jobs\Jobs;
Jobs::define('command', 'app:report')
->named('daily-report')
->dailyAt('02:00')
->queue('reports')
->maxRetries(3)
->dispatch();
dispatch(?string $backend = null) enqueues onto the named backend (or the configured default) and
returns the backend-assigned id. toDefinition() materialises an immutable JobDefinition without
dispatching.
Builder methods¶
v1 |
v3 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
identical helpers on |
|
removed (no built-in notifications) |
|
removed (compose explicitly) |
— |
|
— |
|
Handlers¶
Old handlers extended the Job god-object. v3 handlers implement JobHandlerInterface and receive
an immutable JobContext — no scheduling or queue state.
Old (v1):
class MyJob extends \Daycry\Jobs\Job
{
public function handle($payload)
{
// ...
}
}
v3:
use Daycry\Jobs\Handlers\AbstractJobHandler;
use Daycry\Jobs\Execution\JobContext;
final class MyHandler extends AbstractJobHandler
{
public function handle(JobContext $ctx): mixed
{
$payload = $ctx->payload; // plus $ctx->name, $ctx->queue, $ctx->attempt, $ctx->meta
// ... business logic; throw to signal failure ...
return 'done';
}
}
Register the key in Config\Jobs::$handlers:
public array $handlers = [
'command' => CommandHandler::class,
'myhandler' => \App\Jobs\MyHandler::class,
];
For typed payloads, extend TypedJobHandler and declare payloadType(); the payload is rehydrated
into your DTO before run() is called.
Scheduling (cron)¶
Old: jobs were registered on the V1 Scheduler. v3 registers them in Config\Jobs::init():
use Daycry\Jobs\Cron\Scheduler;
public function init(Scheduler $scheduler): void
{
$scheduler->define('command', 'app:report')
->named('daily-report')
->dailyAt('02:00')
->queue('reports')
->maxRetries(3);
}
Run the scheduler every minute from system cron:
* * * * * cd /path/to/app && php spark jobs:cronjob:run >> /dev/null 2>&1
Definitions with a queue() are enqueued; the rest run inline. The runner honours
enabled()/environments() and resolves dependsOn() in topological order.
Resolving a backend directly¶
Old: QueueManager::instance()->get('redis'). v3:
use Daycry\Jobs\Jobs;
$backend = Jobs::backend('redis'); // or Jobs::backend() for the default worker
$id = $backend->enqueue($definition);
CLI command mapping¶
v1 |
v3 |
|---|---|
|
|
|
|
|
|
|
removed — control scheduling via |
|
removed — use your metrics collector |
|
|
The worker shuts down gracefully on SIGTERM/SIGINT, applies a circuit breaker per backend, and honours per-queue rate limits.
Configuration changes¶
Removed:
$logPerformance,$log,$loggers,$filePath,$maxLogsPerJob,$sensitiveKeys,$maxOutputLength,$batchSize,$workers(now$backends),$jobs(now$handlers), and the email/notification settings.Added:
$handlers,$backends,$queueHandlers(per-queue allowlist),$allowedEvents,$allowAllShellCommands,$signingKey,$verifyEnvelopeSignature,$idempotencyTtl,$databaseVisibilityTimeout,$metricsCollector.Security defaults:
ShellHandleris now deny-by-default ($allowedShellCommands = []rejects everything);EventHandlerrequires$allowedEvents; envelope signature verification is on by default. See Security for the full model.
See Configuration for the complete, current list, and Concurrency & Resilience for the locking/breaker/rate-limit controls.
Suggested migration steps¶
Replace
new Job(...)->enqueue(...)call sites withJobs::define(...)->queue(...)->dispatch().Convert each
Jobsubclass into aJobHandlerInterfaceimplementation and register its key inConfig\Jobs::$handlers.Move scheduled-job registration into
Config\Jobs::init()using the v3Scheduler.Update
Config\Jobs: rename$jobs→$handlers,$workers→$backends; add the security allowlists; remove logger/notification/batch settings.Set
JOBS_SIGNING_KEY(or$signingKey) so envelope signing is active in production.Update crontab/supervisor entries:
jobs:queue:run→jobs:queue:work,jobs:redis:reap-stuck→jobs:queue:reap.Make handlers idempotent; add
idempotencyKey()where a duplicate run must be prevented.