Очереди Laravel: Как обработать один набор заданий только после обработки другого набора заданий?

#php #laravel

#php #laravel

Вопрос:

У меня есть два набора заданий:

  • Set1: Задание A, задание B, задание C
  • Набор 2: Задание D, задание E, задание F

Как я могу обработать все задания в Set1, а затем обработать задания в Set2?

Я попробовал связать задания в цепочку. Но цепочка заданий прекращает обработку заданий, если предыдущее задание выполнено с ошибкой. Я хочу обработать их все, даже если одно из них завершилось с ошибкой.

Он должен обрабатывать все задания в Set1(A, B, C), и процесс B и C не должен останавливаться, если процесс задания A завершился неудачей. Когда все задания из Set1 обработаны (независимо от того, завершились неудачей или успехом) Он должен забирать задания в Set2 для обработки.

Порядок заданий здесь не является приоритетным. Они могут обрабатываться в любом порядке.
Единственным правилом является то, что задания в Set2 должны обрабатываться только после обработки всех заданий в Set1.

Я не могу работать с отложенной отправкой, потому что время, затрачиваемое на обработку набора 1 заданий, варьируется очень сильно.

Ответ №1:

Теперь это можно сделать с помощью пакетной обработки заданий в Laravel 8.x:

 $batch = Bus::batch([
    new ImportCsv(1, 100),
    new ImportCsv(101, 200),
    new ImportCsv(201, 300),
    new ImportCsv(301, 400),
    new ImportCsv(401, 500),
])->then(function (Batch $batch) {
    // All jobs completed successfully...
})->catch(function (Batch $batch, Throwable $e) {
    // First batch job failure detected...
})->finally(function (Batch $batch) {
    // The batch has finished executing...
})->dispatch();
  

Ответ №2:

Цепочка заданий в Laravel основана на том факте, что она не будет выполнять следующие задания, если текущее не выполняется.

Вы можете использовать события. У каждого задания есть 2 метода handle() и failed() . Вы можете генерировать события либо при успешном выполнении задания, либо при сбое. Смотрите пример ниже :

Например :

 <?php

namespace AppJobs;

use Exception;
use AppSomething;
use IlluminateBusQueueable;
use IlluminateQueueSerializesModels;
use IlluminateQueueInteractsWithQueue;
use IlluminateContractsQueueShouldQueue;

class JobA implements ShouldQueue
{
    use InteractsWithQueue, Queueable, SerializesModels;

    protected $something;

    /**
     * Create a new job instance.
     *
     * @param  Something $somethin
     * @return void
     */
    public function __construct(Something $something)
    {
        $this->something = $something;
    }

    /**
     * Execute the job.
     *
     * @param  AudioProcessor  $processor
     * @return void
     */
    public function handle()
    {
        // Execute Job on something
        event(new JobAHandled($something));
    }

    /**
     * The job failed to process.
     *
     * @param  Exception  $exception
     * @return void
     */
    public function failed(Exception $exception)
    {
        // Send user notification of failure, etc...
        event(new JobAFailed($something, $e));
    }
}
  

Теперь вы можете вызвать следующее задание, прослушав события JobAHandled и JobAFailed . Это даст вам контроль над тем, что даже если вы продолжаете выполнение следующего задания, вы знаете, что предыдущее задание завершилось неудачей. При необходимости вы можете зарегистрировать это.

Затем вы можете сделать то же самое для других заданий, независимо от набора, в котором оно находится.

Также убедитесь, что если вы попробуете выполнить задание, то дальнейшие задания будут выполнены снова, поскольку, учитывая ваш случай, событие failed также выполнит следующее задание.

Комментарии:

1. Это приведет к появлению событий для конкретного задания. Как я могу узнать, что все задания в определенном наборе обработаны? чего я пытаюсь достичь, так это обрабатывать задания D, E, F только после обработки заданий A, B, C.

2. @SrinathReddyDudi вы когда-нибудь находили решение этой проблемы?

3. @Isaiahiroko Нет. Самое близкое, к чему я могу подойти, — это отложить обработку заданий set 2 с максимальным количеством времени, которое требуется для завершения заданий set 1.

4. спасибо @SrinathReddyDudi. В конечном итоге может вернуться к этому.

Ответ №3:

Идея заключалась бы в создании задания JobSet и задания JobWorker.

Таким образом, набор заданий принимает ваш новый JobWorker («A»), JobWorker («B»), JobWorker («C») в качестве аргумента, а затем отправляет их все.

 dispatch(new JobSet(new JobWorker("A"), new JobWorker("B"), new JobWorker("C")));
  

и задание «Набор заданий» для вдохновения

 class JobSet implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    private $a;
    private $b;
    private $c;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(JobWorker $a, JobWorker $b, JobWorker $c)
    {
        $this->a = $a;
        $this->b = $b;
        $this->c = $c;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        dispatch($this->a);
        dispatch($this->b);
        dispatch($this->c);
    }
}
  

Комментарии:

1. Я думаю, что это для отправки набора заданий. Мой вопрос заключается в том, как обрабатывать определенный набор заданий только после обработки всех заданий в предыдущем наборе?

Ответ №4:

Вы можете отправлять их в разные очереди:

 A::dispatch()->onQueue('set1');
B::dispatch()->onQueue('set1');
C::dispatch()->onQueue('set1');

D::dispatch()->onQueue('set2');
E::dispatch()->onQueue('set2');
F::dispatch()->onQueue('set2');
  

и запустите worker, который проверяет, что set1 пуст, прежде чем проверять set2:

 php artisan queue:work --queue=set1,set2
  

Чтобы запустить worker, который проверяет, что все задания high очереди обработаны, прежде чем переходить к любым заданиям в low очереди, передайте work команде список имен очередей, разделенных запятыми:

 php artisan queue:work --queue=high,low
  

https://laravel.com/docs/5.8/queues#running-the-queue-worker

Редактировать:

Вы можете решить, что set1 задания от пользователя 2 задерживают set2 задания от пользователя 1, запустив больше рабочих.

Комментарии:

1. Это работает только для одного экземпляра каждого набора. Например, если есть десять пользователей, и они отправили разные экземпляры set1 и set2, то задания set2 будут обработаны только в том случае, если очередь set1 пуста. Это означает, что задания в set2 должны ждать, пока не будут обработаны все задания в set1. Это заставляет каждое задание в очереди set2 каждого пользователя ждать, пока не будут обработаны все задания в очереди set1. Я хочу, чтобы они обрабатывали задания, как только обрабатываются все задания в очереди set1, которая принадлежит этому пользователю. Нет, пока не будут обработаны все задания в очереди set1.

2. @SrinathReddyDudi это могло бы помочь обновить вопрос, потому что там нет упоминания об очередях для каждого пользователя. Если я вас правильно понимаю, то я не могу представить, почему вы хотели бы сделать это именно так; конкретный пример того, почему это должно работать именно так, может быть полезен. Почему порядок вообще имеет значение, если заданиям set2 для конкретного пользователя разрешено обрабатывать независимо от того, были ли успешными их задания set1 ? Если другие пользователи, добавляющие задания set1, задерживают обработку заданий set2, разве вы не можете просто запустить больше рабочих, чтобы очередь не была постоянно заполнена?