vincent15000's avatar

Sale funnel and asynchronous pipeline

Hello,

I'm looking for a way to create an asynchronous pipeline for a sale funnel.

return Pipeline::send($cart)
    ->through([
        ReserveStock::class,
        CreateOrder::class,
        PayOrder::class,
        CommitStock::class,
        ClearCart::class,
        NotifyOrderConfirmation::class,
    ])
    ->thenReturn();

1 - Stock reservation is triggered by an action : the user clicks on a button to validate his / her cart. 2 - If the stock reservation is successful, it will automatically create an order.* 3 - Then the payment needs the user to do the payment action. 4 - If the payment is successful, then it will automatically commit the stock, clear the cart and send a email to notify the user that the order is confirmed.

So the only real possible synchronous pipeline is this one.

return Pipeline::send($cart)
    ->through([
        CommitStock::class,
        ClearCart::class,
        NotifyOrderConfirmation::class,
    ])
    ->thenReturn();

How is it possible to create an asynchronous pipeline with Laravel so that all steps can be in the pipeline ?

Thanks for your help.

V

0 likes
5 replies
LaryAI's avatar
Level 58

Certainly! If you want to handle a sales funnel as an "asynchronous pipeline" in Laravel, where some steps require user interaction (e.g., payment) and others should run automatically after a trigger, you’ll typically want to combine pipelines with event-driven, queued, and/or state-machine approaches. Here’s how you can approach this:

1. Use jobs for asynchronicity

Each pipeline step can be represented as a queued job. After each important action, you dispatch the next job or wait for a user action.


Step 1: Reserve Stock (User Action)

This is triggered by the user clicking a button. In your controller:

public function reserveStock(Request $request)
{
    $cart = $request->user()->cart;

    // Reserve stock (could also be a job)
    app(ReserveStock::class)->handle($cart);

    // Automatically create order
    CreateOrder::dispatch($cart);

    return response()->json(['message' => 'Stock reserved, order created']);
}

Step 2: Create Order (Automatic, Queued Job)

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

    public $cart;

    public function __construct($cart)
    {
        $this->cart = $cart;
    }

    public function handle()
    {
        // Create order logic
        $order = ...;

        // Next: wait for user action to pay
        // (No auto-dispatch here)
    }
}

Step 3: PayOrder (Wait for User Action)

User is redirected to payment. Once payment succeeds (via webhook, controller callback, etc):

public function handlePaymentSuccess(Order $order)
{
    // Payment succeeded.
    CommitStock::dispatch($order);

    return response()->json(['message' => 'Payment successful, order processing']);
}

Step 4: Commit Stock, Clear Cart, Notify (Chained Queued Jobs)

CommitStock

class CommitStock implements ShouldQueue
{
    public $order;

    public function __construct($order) { $this->order = $order; }

    public function handle()
    {
        // Commit stock logic...

        // Next: clear cart
        ClearCart::dispatch($this->order);
    }
}

ClearCart

class ClearCart implements ShouldQueue
{
    public $order;

    public function __construct($order) { $this->order = $order; }

    public function handle()
    {
        // Clear cart logic...

        // Next: notify customer
        NotifyOrderConfirmation::dispatch($this->order);
    }
}

NotifyOrderConfirmation

class NotifyOrderConfirmation implements ShouldQueue
{
    public $order;

    public function __construct($order) { $this->order = $order; }

    public function handle()
    {
        // Send order confirmation email, etc.
    }
}

2. (Optional) Use State Machine or Status Columns

Track order/cart status (status field: reserved, ordered, pending_payment, paid, committed, etc). Logic can branch based on status.


3. Short summary

Don't try to run all pipeline stages in a sequence if some depend on user actions. Instead, break the process into these steps, chaining them with jobs and invoking each stage as its prerequisites are met (either by user or via job completion).


4. Resources


Key Takeaway

By breaking up your pipeline into individual queued jobs, dispatched in response to system events or user actions, you create an asynchronous pipeline that fits your requirements.

If you'd like a "formal pipeline" implementation, consider an orchestrator class to manage the step-by-step execution and state.

Let me know if you want an example using events instead of jobs, or a more advanced workflow!

martinbean's avatar

@vincent15000 I don’t really understand what you’re asking? What do you want to be asynchronous? A pipeline is not asynchronous by design; it runs each “pipe” in turn.

1 like
vincent15000's avatar

Well ... in a sale funnel, data are transfered from one to another step, some steps can be executed automatically, whereas others need a user action.

As data are transfered from one step to another, I have thought about a pipeline, but pipelines are synchronous. So I wondered if asynchronous pipelines exist or not.

I think that the best solution is really using events / queued jobs.

Glukinho's avatar
Level 30

I use chained queued jobs for this purpose.

1 like

Please or to participate in this conversation.