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