Laravel queue docs: https://laravel.com/docs/master/queues

Jobs

In this guide, the queue driver will be database, you have to config your application to use database.

php artisan queue:table
QUEUE_CONNECTION=database
php artisan migrate

Usage

Create a new Job

php artisan make:job ProcessHeavyServerTask
<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Log;

class ProcessHeavyServerTask implements ShouldQueue
{
  use Dispatchable;
  use InteractsWithQueue;
  use Queueable;
  use SerializesModels;

  /**
   * Create a new job instance.
   */
  public function __construct(
    public mixed $param,
    public mixed $param_alt,
  ) {
  }

  /**
   * Execute the job.
   */
  public function handle()
  {
    // Very heavy server task...

    Log::debug('Success on job '.now());
  }

  public function failed(\Throwable $exception)
  {
    Log::error('Error on job');
  }
}

Call job

<?php

class MainController extends Controller
{
  public function index()
  {
    $param = [];
    $param_alt = true;

    ProcessHeavyServerTask::dispatch($param, $param_alt);
  }
}

Execute

If you change anything into your job, you have to re-run the command. And for EVERY deployment, you have to restart supervisor.

Local

php artisan queue:work --queue

Server

Install supervisor.

Replace app-name with the name of your application.

sudo apt install supervisor -y
cd /etc/supervisor/conf.d
sudo vim /etc/supervisor/conf.d/app-name-worker.conf
/etc/supervisor/conf.d/app-name-worker.conf
[program:app-name-worker]
process_name=%(program_name)s_%(process_num)02d
command=php8.2 /home/USER/www/app-name/artisan queue:work database --sleep=3 --tries=3
autostart=true
autorestart=true
user=USER # www-data
numprocs=1
redirect_stderr=true
stdout_logfile=/home/USER/www/app-name/storage/logs/worker.log
stopwaitsecs=3600

In /etc/supervisor/supervisord.conf, check if this exist.

/etc/supervisor/supervisord.conf
[include]
files = /etc/supervisor/conf.d/*.conf

When you create a new config, use these commands.

sudo supervisorctl reread
sudo supervisorctl update
Manage restart without sudoTo restart supervisor from CI, you have to allow restart without sudo.
sudo vim /etc/supervisor/supervisord.conf
/etc/supervisor/supervisord.conf
[unix_http_server]
; add this line
chown = USER:www-data
sudo service supervisor restart
Now USER can restart supervisor without sudo.
supervisorctl start app-name-worker:app-name-worker_00

When you deploy a new app version, restart supervisor worker with this command.

supervisorctl restart app-name-worker:app-name-worker_00

Example with bookshelves app.

supervisorctl start bookshelves-worker:bookshelves-worker_00
List all workers
supervisorctl

Example of output.

output
app-name-worker:app-name-worker_00                 RUNNING   pid 40598, uptime 0:03:30

Restart it.

supervisorctl start app-name-worker:app-name-worker_00

Add it to CI

Add to your CI config or post-merge Git hook.

.gitlab-ci.yml
deploy-job:
  stage: deploy
  script:
    - supervisorctl restart app-name-worker:app-name-worker_00
  only:
    - main

Schedule

app/Console/Kernel.php
<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use App\Console\Commands\AnyCommand;

class Kernel extends ConsoleKernel
{
  protected function schedule(Schedule $schedule)
  {
    $schedule->command(AnyCommand::class, ['argument', '--option'])->daily();
  }
}

Shell commands

app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
  $schedule->exec('node /home/forge/script.js')->daily();
}

Cheatsheet

List schedule

php artisan schedule:list

Run schedule

php artisan schedule:run

Keep schedule running

php artisan schedule:work

Run in production

Set php version into cron with php8.1. Just use crontab.

crontab -e
* * * * * cd /path/to/project && php8.1 artisan schedule:run >> /dev/null 2>&1