Пакет · thread

Обработчик очереди

Берите задачи из очереди и выполняйте каждую в отдельном фоновом процессе, передавая данные для каждой задачи как аргументы. Впервые с thread? Начните с Быстрого старта.

Опишите задачу

Держите задачу маленькой и сериализуемой — простые данные в конструкторе, ресурсы открываются внутри run() (см. границу сериализации).

src/SendInvoice.php
<?php

use Flytachi\Winter\Thread\Runnable;

class SendInvoice implements Runnable
{
  public function __construct(private int $orderId) {}

  public function run(array $args): void
  {
      $attempt = (int) ($args['attempt'] ?? 1);
      $urgent  = isset($args['urgent']);

      $mailer = new Mailer(); // открывайте ресурсы здесь, а не в конструкторе
      $mailer->sendInvoice($this->orderId, urgent: $urgent);
  }
}

Передавайте аргументы запуска

start() принимает ассоциативный массив. Значения приходят в run() через $args:

  • 'key' => 'value'$args['key'] === 'value' (всегда строка)
  • 'flag' => true$args['flag'] === true (флаг без значения; проверяйте через isset())
  • 'skip' => false или 'skip' => nullисключается из $args
php
$thread = new Thread(new SendInvoice($orderId), 'Billing', 'SendInvoice', "order-{$orderId}");

$thread->start([
  'attempt' => '2',
  'urgent'  => true,   // флаг без значения
  'skip'    => false,  // отбрасывается
]);

Аргументы — строки

Каждое значение передаётся через командную строку, поэтому числа приходят строками — приводите их в run() ((int) $args['attempt']). Принимаются только скаляры и булевы значения; см. справочник по Runnable.

Разбирайте очередь

Один процесс на задачу. Для fire-and-forget — запустили и пошли дальше: вывод по умолчанию идёт в /dev/null, так что pipe вычитывать не нужно:

worker.php
<?php

require 'vendor/autoload.php';

use Flytachi\Winter\Thread\Thread;

// $queue->pull() возвращает id следующего заказа или null, когда очередь пуста
while (($orderId = $queue->pull()) !== null) {
  $thread = new Thread(new SendInvoice($orderId), 'Billing', 'SendInvoice', "order-{$orderId}");
  $thread->start(['attempt' => '1']);
  // без join() — fire and forget; родитель продолжает разбирать очередь
}

Не плодите процессы без ограничения

Один процесс ОС на задачу — нормально при небольших объёмах, но неограниченный цикл может наплодить тысячи процессов. Чтобы ограничить число одновременно работающих, используйте небольшой пул — см. Параллельные задачи.

Связанное