Home > database >  Laravel wait for a specific queued listener to finish then return
Laravel wait for a specific queued listener to finish then return

Time:10-03

I have an Event with a bunch of queued listeners. I Can't run sync because I am calling external APIs etc

Events\Invoice\InvoiceEvent::class => [
    Listeners\Invoice\Listener1::class, // should queue
    Listeners\Invoice\Listener2::class, // should queue
    Listeners\Invoice\Listener3::class, // Should NOT queue......
    Listeners\Invoice\Listener4::class, // should queue
    Listeners\Invoice\Listener5::class, // should queue
],

Calling this event from a controller method.

public function store(Request $request)
{
    $invoice = Invoice::findOrFail($request->id);
    InvoiceEvent::dispatch($invoice); // Async event, it cannot be sync

    return $invoice; // need to return only when Listener3 finish execution
}

return $invoice is dependent on Listener3, otherwise, it will return incomplete data.

How can I return only when Listener3 is finished executing?

I came up with sleep(10); but it's not an ideal solution.

Listener3 saves data from third-party API to the invoices table which needs to be returned, that's why cannot return incomplete invoice data, right now the required data gets added to the invoice but after its return

CodePudding user response:

PHP is natively synchronous. Unless you're pushing those events or listeners to a queue, (i.e. class Listener3 implements ShouldQueue) then they should run in order. However, you might want to rethink the structure of your code.

Listeners are best as reactions to an event, i.e. side effects, running independently from the rest of your application. Jobs, Events and Listeners should not generally return a value (except to halt a series of listeners). In your case, the Invoice is going through multiple steps, including calling a 3rd party API. Ideas:

  1. Create a service class that performs the tasks on the Invoice and returns the invoice to the controller when completed (which then will return the $invoice data to the front end)
  2. If you want the process to be async, consider using a push notification. Dispatch a job which performs the tasks on the Invoice, then alert the front end (e.g. Pusher ) when the invoice is ready to fetch.

CodePudding user response:

There are a way to broadcast your event not queuing it,

into your event class add:

use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;

so your class declaration must implements ShouldBroadcastNow

class NotQueueEvent implements ShouldBroadcastNow { ... }

this spread event without enqueue.

CodePudding user response:

If you want to wait to this method return, you should only don't put it on the queue. Run the event and await the return. Don't know if I understood correctly the problem.

  • Related