0

I currently have an import process that dispatches a series of jobs to a default queue that are initiated by user input via API.

If I add the user id to the queue name when dispatching it will go to a user-specific queue but I have no way of starting a queue worker for that specific queue. Any way to programmatically start a queue:work command to get around this?

Furthermore, I'd like to send a broadcast signal for the individual user once the queue has finished its jobs. My initial thoughts were to implement sending a signal in an event subscriber that monitors that user-specific queue if I can solve the initial question.

I found a partial route here: Polling Laravel Queue after All Jobs are Complete This doesn't fully work because it will keep triggering when the queue is empty. So I'd have to find some way to unsubscribe the event subscriber once it runs once. I'd also have to find a way to subscribe the event subscriber at runtime once the import process has started vs in the Event Subscribe Service Provider as stated in the official Laravel documentation. https://laravel.com/docs/8.x/events#event-subscribers

One approach could be to create a custom table that manages this and then add/remove to it and have the loop event subscriber iterate through that table, and check if the queue is in that table, if so then check to see its size, and if its 0, send the broadcast signal and then remove from the table.

Here are the events that already exist for Queues. https://laravel.com/api/8.x/Illuminate/Queue/Events/Looping.html

What's the best way to approach this?

Start to End: User provides a file to import, I'm interpreting the file, and dispatching jobs that process the data, once jobs are finished, a broadcast signal should be sent to that user saying the import is completed.

1 Answer 1

1

You might want to use the Job Batches functionality

It will let you dispatch jobs and run callback at the end. Here is an exemple from the doc:

$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();   

You can send the Broadcast Event at the end in the Callback

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for sharing this idea. I attempted this, the BatchedJobs appear to execute, but then then/catch statements don't appear to trigger.
if(count($BatchedEntries) > 0) { Bus::batch($BatchedEntries) ->then(function(Batch $batch) { Log::info("ProcessEntries: ".count($batch->successful())." entries processed successfully."); $user = User::where('id', $this->processing_user_id)->first(); $user->notify(new \App\Notifications\ImportCompleted()); }) ->catch(function(Batch $batch) { Log::info("ProcessEntries: ".count($batch->failed())." entries failed to process."); }) ->dispatch();}
Well, for some reason the batch was never dispatching. I ended up installing Laravel Horizon using redis, and configuring the appropriate queues. After this the code mentioned above started working as expected! I ended up using the notification functionality to trigger the broadcast notification so that only that specific user can see that their import was completed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.