Queue / Job Dispatching

Table of contents

  1. Overview
  2. Features
  3. Real-World Example: Queued Welcome Email
  4. Creating a Job Class
  5. Configuration
  6. Starting the Worker
  7. Job Lifecycle
  8. Failed Jobs
  9. Queue Table Migration
  10. 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() or dispatch()
  • 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() and maxAttempts()
  • After final failure, it’s marked with failed_at
  • You can inspect job state in the queue table


9. πŸ“‹ Queue Table Migration Table of Contents

To generate the queue table migration:

php console queue:migration

Columns include:

  • queue – queue name
  • payload – job data
  • attempts, available_at, reserved_at, failed_at
  • exception – 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');