Search code examples
phplaravellaravel-11laravel-queueamazon-selling-partner-api

Laravel 11.x Queue chain functions


I'am using Laravel 11.x as Framework and currently trying to figure out "the best" way to handle a big process from the amazon sp-api. I want to handle the API Requests within Jobs and want to chain them for a bigger process. E.g. the process of getting a shipping label for an Fullfilment package need like ~16 steps. (a horrible thing..)

I create Jobs for each request and want to chain them as needed. e.g. each POST Request must follow a request to the operationStatus Ressource which should anwser finally with SUCCESS or FAILED.

So the question is, can I capsulate smaller processes in functions and chain them finally for the big process? E.g. this are three functions which should be processed one after another:

public function createInboundPlan(Request $request){
    $uuid = Str::orderedUuid()->toString();
    Bus::chain([
        new CreateInboundPlan($uuid, $request),
        new GetInboundOperationStatus($uuid, Cache::pull($uuid.':'.'CreateInboundPlan'.':'.'operationId'), $request),
    ])->catch(function (Throwable $e) {
        // A job within the chain has failed...
    })->dispatch();
}

public function generatePackingOptions(string $inboundPlanId, Request $request){
    $uuid = Str::orderedUuid()->toString();
    Bus::chain([
        new GeneratePackingOptions($uuid, $inboundPlanId, $request),
        new GetInboundOperationStatus($uuid, Cache::pull($uuid.':'.'GeneratePackingOptions'.':'.'operationId'), $request),
    ])->catch(function (Throwable $e) {
        // A job within the chain has failed...
    })->dispatch();
}

public function listPackingOptions(string $inboundPlanId, Request $request){
    $uuid = Str::orderedUuid()->toString();
    Bus::chain([
        new ListPackingOptions($uuid, $inboundPlanId, $request),
        new SelectInboundPackingOption($uuid, Cache::pull($uuid.':'.'ListPackingOptions'.':'.'packingOptions'), $request),
    ])->catch(function (Throwable $e) {
        // A job within the chain has failed...
    })->dispatch();
}

Is there a way to archive something like this?

Bus::chain([
$this->createInboundPlan($request),
$this->generatePackingOptions($inboundPlanId, $request),
$this->generatelistPackingOptions($inboundPlanId, $request)
])->dispatch();

Currently the only Idea I have is to not work with functions and instead create "parent" jobs, which get chained. I mean I could just create a big chain for that big process and don't capsulate everything, but I may need single parts of this later again and I like the idea of that structure^^

Greetings


Solution

  • For example

    <?php
    
    require __DIR__.'/vendor/autoload.php';
    
    use Illuminate\Contracts\Bus\Dispatcher;
    use Illuminate\Foundation\Queue\Queueable;
    use Illuminate\Contracts\Queue\ShouldQueue;
    use Illuminate\Pipeline\Pipeline;
    use Illuminate\Support\Str;
    
    class RequestOptions
    {
        protected $planId;
        protected $uuid;
    
        // etc properties
    
        public function __construct(string $uuid)
        {
            $this->uuid = $uuid;
        }
    
        /**
         * @param mixed $planId
         */
        public function setPlanId($planId): void
        {
            $this->planId = $planId;
        }
    
    }
    
    class InboundPlanProcess implements ShouldQueue
    {
        use Queueable;
    
        protected array $steps = [];
    
        public function __construct(array $steps)
        {
            // each step implement your interface
            $this->steps = $steps;
        }
    
        public function handle(string $uuid)
        {
            $options = new RequestOptions($uuid);
    
            return app(Pipeline::class)
                ->send($options)
                ->through($this->steps)
                ->thenReturn();
        }
    }
    
    interface StepInterface
    {
    
    }
    
    class CreateInboundPlan implements StepInterface
    {
        public function __invoke(RequestOptions $options, $next)
        {
            $options->setPlanId(123);
    
            return $next($options);
        }
    }
    
    class GeneratePackingOptions implements StepInterface
    {
        public function __invoke(RequestOptions $options, $next)
        {
            // generate packing options
    
            return $next($options);
        }
    }
    $uuid = Str::orderedUuid()->toString();
    
    $process = new InboundPlanProcess([
        new CreateInboundPlan(),
        new GeneratePackingOptions(),
    
    // OR
    
    //    function (RequestOptions $options, $next) {
    //        $options->setPlanId(123);
    //
    //        return $next($options);
    //    },
    //    function (RequestOptions $options, $next) {
    //        return $next($options);
    //    },
    ]);
    
    
    $result = dispatch($process);