Queue / Job Dispatching
Table of contents
- Overview
- Features
- Real-World Example: Queued Welcome Email
- Creating a Job Class
- Configuration
- Starting the Worker
- Job Lifecycle
- Failed Jobs
- Queue Table Migration
- Bonus: Dispatch Helper (Optional)
1. Overview Table of Contents
Chappy.php includes a robust queue system that supports asynchronous job processing using either a database or Redis backend.
Use queues to defer time-consuming work like emails, notifications, and data processing β improving user experience and application responsiveness.
2. π Features Table of Contents
- Queueable jobs with delay and retry support
- Database or Redis drivers
- Max attempt limits and backoff strategies
- Job scaffolding via CLI
- Graceful shutdown handling
- Fully integrated CLI worker (
queue:worker)
3. β Real-World Example: Queued Welcome Email Table of Contents
You can enqueue a job inside a service layer like this:
use App\Jobs\SendWelcomeEmail;
use Core\Lib\Queue\QueueManager;
class UserService {
public static function queueWelcomeMailer(int $user_id): void {
$queue = new QueueManager();
$job = new SendWelcomeEmail(['user_id' => $user_id], 0); // delay 0s
$queue->push('default', $job->toPayload());
}
}
This is invoked inside the registerAction() method after user creation:
public function registerAction(): void {
$user = new Users();
if ($this->request->isPost()) {
$this->request->csrfCheck();
...
$user->save();
if ($user->validationPassed()) {
UserService::queueWelcomeMailer((int)$user->id);
if ($uploads) {
ProfileImages::uploadProfileImage($user->id, $uploads);
}
redirect('auth.login');
}
}
$this->view->user = $user;
$this->view->displayErrors = $user->getErrorMessages();
$this->view->render('auth.register');
}
4. π Creating a Job Class Table of Contents
Generate a job using:
php console make:job SendWelcomeEmail
Edit app/Jobs/SendWelcomeEmail.php handle function:
class SendWelcomeEmail implements QueueableJobInterface {
protected array $data;
protected int $delayInSeconds;
protected int $maxAttempts;
public function __construct(array $data, int $delayInSeconds = 0, int $maxAttempts = 3) {
$this->data = $data;
$this->delayInSeconds = $delayInSeconds;
$this->maxAttempts = $maxAttempts;
}
public function handle(): void {
$user = Users::findById($this->data['user_id']);
Tools::info("Sending welcome email to {$user->username} at {$user->email}", "info");
WelcomeMailer::sendTo($user);
}
public function backoff(): int|array {
return [10, 30, 60]; // Retry intervals in seconds
}
public function delay(): int {
return $this->delayInSeconds;
}
public function maxAttempts(): int {
return $this->maxAttempts;
}
public function toPayload(): array {
return [
'job' => static::class,
'data' => $this->data,
'available_at' => time() + $this->delay(),
'max_attempts' => $this->maxAttempts()
];
}
}
5. βοΈ Configuration Table of Contents
Edit your queue configuration in the .env file:
QUEUE_DRIVER='database' # or 'redis'
MAX_ATTEMPTS=3
REDIS_HOST='127.0.0.1'
REDIS_PORT='6379'
6. π§ Starting the Worker Table of Contents
Start a worker process to handle jobs:
php console queue:worker
Optional arguments:
| Flag | Description |
|---|---|
--once |
Run only one job then exit |
--max=100 |
Run up to 100 iterations |
--queue=emails |
Run only jobs in this queue |
Example:
php console queue:worker --queue=default --max=50
7. π§© Job Lifecycle Table of Contents
- A. Job is enqueued using
push()ordispatch() - B. Worker pops and reserves the next eligible job
- C. Calls
handle()on the job instance - D. If success β deletes the job
- E. If failure β retries with backoff, up to
maxAttempts
8. π Failed Jobs Table of Contents
If a job fails:
- It is retried based on
backoff()andmaxAttempts() - After final failure, itβs marked with
failed_at - You can inspect job state in the
queuetable
9. π Queue Table Migration Table of Contents
To generate the queue table migration:
php console queue:migration
Columns include:
queueβ queue namepayloadβ job dataattempts,available_at,reserved_at,failed_atexceptionβ captured error message- Laravel-style timestamps
10. β¨ Bonus: Dispatch Helper (Optional) Table of Contents
While you can use push() like this:
$queue->push('emails', $job->toPayload());
You can also dispatch raw class + data:
$queue->dispatch(SendWelcomeEmail::class, ['user_id' => 1], 'emails');