Background Jobs

Background Jobs, Queues and Scheduled Tasks

Often the fix is to move work out of the request: it queues a job and returns, and a worker sends the mail. Laravel 2,157 's queues are Queues and Scheduling, cron is Cron, Logs and journalctl and supervising workers is Processes and Monitoring. A CLI worker can also start processes itself:

Forking workers and piping data through a shell pipelinePHP
<?php
$t0 = hrtime(true);
foreach (['resize' => 0.3, 'email' => 0.2, 'report' => 0.4] as $job => $secs) {
  $pid = pcntl_fork();
  if ($pid === 0) { usleep((int) ($secs * 1e6)); exit(0); }   // child: one job, then exit
  $kids[$pid] = $job;                                        // parent: remember who does what
}
while ($kids) {
  $pid = pcntl_wait($status);                                // blocks until any child exits
  printf("%.2f s  %s exited %d\n", (hrtime(true) - $t0) / 1e9, $kids[$pid],
    pcntl_wexitstatus($status));
  unset($kids[$pid]);
}
$proc = proc_open(['sh', '-c', 'sort | uniq -c | sort -rn'], [['pipe', 'r'], ['pipe', 'w']],
  $io);                                                      // argv array: no shell quoting
fwrite($io[0], "php\nmysql\nphp\nphp\n") && fclose($io[0]);   // EOF lets sort answer
echo stream_get_contents($io[1]), 'exit code ', proc_close($proc), "\n";
Output
0.22 s  email exited 0
0.32 s  resize exited 0
0.42 s  report exited 0
      3 php
      1 mysql
exit code 0

pcntl_fork() returns 0 in the child and its PID in the parent. The jobs ran in parallel and were reaped as they finished. Reconnect to MySQL 524 in each child, since connections are inherited. The parallel extension (1.2.15) adds threads but needs a ZTS build; Ubuntu 225 's PHP is NTS.