laravel / ideas

Issues board used for Laravel internals discussions.
938 stars 28 forks source link

Allow batch to be passed in a chain #2499

Closed ajcastro closed 3 years ago

ajcastro commented 3 years ago

Link: https://www.reddit.com/r/laravel/comments/kai9xy/is_it_possible_to_chain_a_batch_of_jobs_within/

This doesn't work:

Bus::chain([ 
  new SerialJobSetup, 
  new SerialJob2,
  Bus::batch([
    new ParallelJob(1), // Runs in Parallel on different queue workers
    new ParallelJob(2), // Runs in Parallel on different queue workers
    new ParallelJob(3), // Runs in Parallel on different queue workers
    new ParallelJob(4), // Runs in Parallel on different queue workers
    ...
  ]),
  new SerialJob3, // Continues to run the chain once all parallel jobs above have completed
  new SerialJobCleanup,
])->dispatch();

Currently this can be solved by wrapping the job inside a closure:

Bus::chain([ 
  new SerialJobSetup, 
  new SerialJob2,
  function () {
    Bus::batch([
      new ParallelJob(1), // Runs in Parallel on different queue workers
      new ParallelJob(2), // Runs in Parallel on different queue workers
      new ParallelJob(3), // Runs in Parallel on different queue workers
      new ParallelJob(4), // Runs in Parallel on different queue workers
      ...
    ])->dispatch();
  },
  new SerialJob3, // Continues to run the chain once all parallel jobs above have completed
  new SerialJobCleanup,
])->dispatch();

Possible Proposal:

Bus::chain([ 
  new SerialJobSetup, 
  new SerialJob2,
  Bus::chainableBatch([
    new ParallelJob(1), // Runs in Parallel on different queue workers
    new ParallelJob(2), // Runs in Parallel on different queue workers
    new ParallelJob(3), // Runs in Parallel on different queue workers
    new ParallelJob(4), // Runs in Parallel on different queue workers
    ...
  ]),
  new SerialJob3, // Continues to run the chain once all parallel jobs above have completed
  new SerialJobCleanup,
])->dispatch();

Or we can add a different method instead of chainableBatch. which wraps the batch of jobs in a closure or something so they can be passed into the chain

ajcastro commented 3 years ago

I have a helper only for array of batches, this is different from "array of mixed normal jobs and batched jobs":

if (!function_exists('chain_batches')) {
    function chain_batches($batches)
    {
        [$batch1, $batch2] = $batches;

        $bus = \Illuminate\Support\Facades\Bus::batch($batch1);

        if ($batch2) {
            $bus->then(function () use ($batches) {
                array_shift($batches);
                chain_batches($batches);
            });
        }

        return $bus->dispatch();
    }
}

Usage:

chain_batches([
   // Batch 1
  [
    new FirstJobsToProcessInParallel(),
    new FirstJobsToProcessInParallel(),
    new FirstJobsToProcessInParallel(),
  ], 
  // Batch 2
  [
    new SecondJobsToProcessInParallel(),
    new SecondJobsToProcessInParallel(),
    new SecondJobsToProcessInParallel(),
  ], 
  // Batch 3
  [
    new ThirdJobsToProcessInParallel(),
    new ThirdJobsToProcessInParallel(),
    new ThirdJobsToProcessInParallel(),
  ], 
]);
themsaid commented 3 years ago

Using a closure is perfectly fine in this situation.