DebugFactor.com | Forum

Exception: Serialization of 'Closure' is not allowed while trying to pass $request to Laravel job dispatch method

I am trying to convert an existing API to a job in Laravel.
The API is a long-running job actually, and I am getting frequent timeouts when I host this application in google cloud.

The job is dispatched as from the API handler:

BinanceControllerJob::dispatch($request);

This is how I have defined the constructor and handle the function of BinanceControllerJob.php

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

    protected $request;

    public function __construct($request)
    {
        $this->request= $request;
    }
    public function handle()
    {
        $binanceController = new BinanceController();
        $binanceController->getTrades($this->request);
    }
}

I am getting the following error while invoking the API and the job is not created in Jobs table.

[2021-04-22 16:34:22] local.ERROR: Exception: Serialization of 'Closure' is not allowed in \backend\vendor\laravel\framework\src\Illuminate\Queue\Queue.php:139
Stack trace:
#0 \backend\vendor\laravel\framework\src\Illuminate\Queue\Queue.php(139): serialize(Object(App\Jobs\BinanceControllerJob))
#1 \backend\vendor\laravel\framework\src\Illuminate\Queue\Queue.php(110): Illuminate\Queue\Queue->createObjectPayload(Object(App\Jobs\BinanceControllerJob), 'default')
#2 \backend\vendor\laravel\framework\src\Illuminate\Queue\Queue.php(88): Illuminate\Queue\Queue->createPayloadArray(Object(App\Jobs\BinanceControllerJob), 'default', '')
#3 \backend\vendor\laravel\framework\src\Illuminate\Queue\DatabaseQueue.php(82): Illuminate\Queue\Queue->createPayload(Object(App\Jobs\BinanceControllerJob), 'default', '')
#4 \backend\vendor\laravel\framework\src\Illuminate\Bus\Dispatcher.php(184): Illuminate\Queue\DatabaseQueue->push(Object(App\Jobs\BinanceControllerJob))
#5 \backend\vendor\laravel\framework\src\Illuminate\Bus\Dispatcher.php(160): Illuminate\Bus\Dispatcher->pushCommandToQueue(Object(Illuminate\Queue\DatabaseQueue), Object(App\Jobs\BinanceControllerJob))
#6 \backend\vendor\laravel\framework\src\Illuminate\Bus\Dispatcher.php(73): Illuminate\Bus\Dispatcher->dispatchToQueue(Object(App\Jobs\BinanceControllerJob))
#7 \backend\vendor\laravel\framework\src\Illuminate\Foundation\Bus\PendingDispatch.php(112): Illuminate\Bus\Dispatcher->dispatch(Object(App\Jobs\BinanceControllerJob))
#8 \backend\vendor\laravel\framework\src\Illuminate\Foundation\Bus\Dispatchable.php(16): Illuminate\Foundation\Bus\PendingDispatch->__destruct()
#9 \backend\app\Http\Controllers\Exchanges\BinanceController.php(314): App\Jobs\BinanceControllerJob::dispatch(Object(Illuminate\Http\Request))
#10 [internal function]: App\Http\Controllers\Exchanges\BinanceController->dispatchBinanceControllerJob(Object(Illuminate\Http\Request), 'agent')
#11 \backend\vendor\laravel\framework\src\Illuminate\Routing\Controller.php(54): call_user_func_array(Array, Array)
#12 \backend\vendor\laravel\framework\src\Illuminate\Routing\ControllerDispatcher.php(45): Illuminate\Routing\Controller->callAction('dispatchBinance...', Array)
#13 \backend\vendor\laravel\framework\src\Illuminate\Routing\Route.php(219): Illuminate\Routing\ControllerDispatcher->dispatch(Object(Illuminate\Routing\Route), Object(App\Http\Controllers\Exchanges\BinanceController), 'dispatchBinance...')
#14 \backend\vendor\laravel\framework\src\Illuminate\Routing\Route.php(176): Illuminate\Routing\Route->runController()

The error message indicates that the request object cannot be serialized. Only serializable objects can be passed to Laravel Jobs.

You could try to extract the required parameters from $request object and wrap it to a serializable object and pass it to the job.

Here is an example that worked for me.

When you dispatch the job, send only the required account_id to the Job

BinanceControllerJob::dispatch($request->input('account_id'));

Inside the Job class constructor assign the account_id to an object level protected variable.

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

And in the handle function, retrieve the account_id and add it the $request object and pass it along to where ever you want.

public function handle()
{
    $request = new Request();
    $request["account_id"] =  $this->account_id;
    $binanceController = new BinanceController();
   $binanceController->getTrades($request);
}

Hope this helps!