laravel / framework

The Laravel Framework.
https://laravel.com
MIT License
32.52k stars 11.02k forks source link

[8.x] Failed to send queued notifications with `RateLimited` middleware: `Exception: Serialization of 'Closure' is not allowed` #35868

Closed chuangbo closed 3 years ago

chuangbo commented 3 years ago

Description:

The notification channel we are using is limiting 20 requests per minute. Since job middleware are supported for queued notifications (#30070), we would like to leverage Illuminate\Queue\Middleware\RateLimited middleware for the queued notification, as described in https://laravel.com/docs/8.x/queues#rate-limiting. But it throws exception: Serialization of 'Closure' is not allowed.

Steps To Reproduce:

  1. Define a RateLimiter in the boot method of AppServiceProvider
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    RateLimiter::for('notification-channel-xxx', function ($job) {
        return Limit::perMinute(20);
    });
}
  1. Attach the rate limiter to the notification
<?php

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\Middleware\RateLimited;

class SomeMessage extends Notification implements ShouldQueue
{
    use Queueable;

    /**
     * Get the middleware the job should pass through.
     *
     * @return array
     */
    public function middleware()
    {
        return [new RateLimited('notification-channel-xxx')];
    }
}
  1. Send notification
$user->notify(new SomeMessage('test'))
// Exception with message 'Serialization of 'Closure' is not allowed'
themsaid commented 3 years ago

You need to share the full stack trace.

taylorotwell commented 3 years ago

Please re-open with more information as noted by @themsaid

chuangbo commented 3 years ago

Thank you for the notes. The full stack trace is attached as below:

Exception {#7246
  #message: "Serialization of 'Closure' is not allowed"
  #code: 0
  #file: "/app/vendor/laravel/framework/src/Illuminate/Queue/Queue.php"
  #line: 157
  trace: {
    /app/vendor/laravel/framework/src/Illuminate/Queue/Queue.php:157 { …}
    /app/vendor/laravel/framework/src/Illuminate/Queue/Queue.php:127 { …}
    /app/vendor/laravel/framework/src/Illuminate/Queue/Queue.php:104 { …}
    /app/vendor/laravel/framework/src/Illuminate/Queue/SyncQueue.php:38 { …}
    /app/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php:251 { …}
    /app/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php:227 { …}
    /app/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php:77 { …}
    /app/vendor/laravel/framework/src/Illuminate/Notifications/NotificationSender.php:212 { …}
    /app/vendor/laravel/framework/src/Illuminate/Notifications/NotificationSender.php:76 { …}
    /app/vendor/laravel/framework/src/Illuminate/Notifications/ChannelManager.php:39 { …}
    /app/vendor/laravel/framework/src/Illuminate/Notifications/RoutesNotifications.php:18 { …}
    /app/vendor/psy/psysh/src/ExecutionLoopClosure.php:55 { …}
    /app/vendor/psy/psysh/src/ExecutionLoopClosure.php:55 { …}
    /app/vendor/psy/psysh/src/ExecutionClosure.php:96 { …}
    /app/vendor/psy/psysh/src/Shell.php:370 { …}
    /app/vendor/psy/psysh/src/Shell.php:341 { …}
    /app/vendor/symfony/console/Application.php:166 { …}
    /app/vendor/psy/psysh/src/Shell.php:316 { …}
    /app/vendor/laravel/tinker/src/Console/TinkerCommand.php:81 { …}
    /app/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:36 { …}
    /app/vendor/laravel/framework/src/Illuminate/Container/Util.php:40 { …}
    /app/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:93 { …}
    /app/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php:37 { …}
    /app/vendor/laravel/framework/src/Illuminate/Container/Container.php:610 { …}
    /app/vendor/laravel/framework/src/Illuminate/Console/Command.php:136 { …}
    /app/vendor/symfony/console/Command/Command.php:255 { …}
    /app/vendor/laravel/framework/src/Illuminate/Console/Command.php:121 { …}
    /app/vendor/symfony/console/Application.php:971 { …}
    /app/vendor/symfony/console/Application.php:290 { …}
    /app/vendor/symfony/console/Application.php:166 { …}
    /app/vendor/laravel/framework/src/Illuminate/Console/Application.php:93 { …}
    /app/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php:129 { …}
    /app/artisan:37 {
      ›     $input = new Symfony\Component\Console\Input\ArgvInput,
      ›     new Symfony\Component\Console\Output\ConsoleOutput
      › );
      arguments: {
        $input: Symfony\Component\Console\Input\ArgvInput {#25 …}
        $output: Symfony\Component\Console\Output\ConsoleOutput {#23 …}
      }
    }
  }
}
chuangbo commented 3 years ago

@taylorotwell @themsaid Is it possible that we re-open this?

driesvints commented 3 years ago

I see you're using Tinker. Are you maybe using the wrong way to send these jobs?

See https://laravel.com/docs/8.x/artisan#usage

Screenshot 2021-01-15 at 10 22 19
chuangbo commented 3 years ago

@driesvints It wasn't from the dispatch helper, it was $user->notify(new SomeMessage('test')) from tinker. But I'll try to call it from a normal route instead.

chuangbo commented 3 years ago

Tried call $user->notify(new SomeMessage('test')) from a http route seems throwing the same exception.

[2021-01-15 22:36:29] local.ERROR: Serialization of 'Closure' is not allowed {"userId":4,"exception":"[object] (Exception(code: 0): Serialization of 'Closure' is not allowed at /app/vendor/laravel/framework/src/Illuminate/Queue/Queue.php:156)
[stacktrace]
#0 /app/vendor/laravel/framework/src/Illuminate/Queue/Queue.php(156): serialize(Object(Illuminate\\Notifications\\SendQueuedNotifications))
#1 /app/vendor/laravel/framework/src/Illuminate/Queue/Queue.php(126): Illuminate\\Queue\\Queue->createObjectPayload(Object(Illuminate\\Notifications\\SendQueuedNotifications), NULL)
#2 /app/vendor/laravel/framework/src/Illuminate/Queue/Queue.php(104): Illuminate\\Queue\\Queue->createPayloadArray(Object(Illuminate\\Notifications\\SendQueuedNotifications), NULL, '')
#3 /app/vendor/laravel/framework/src/Illuminate/Queue/SyncQueue.php(38): Illuminate\\Queue\\Queue->createPayload(Object(Illuminate\\Notifications\\SendQueuedNotifications), NULL, '')
#4 /app/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php(251): Illuminate\\Queue\\SyncQueue->push(Object(Illuminate\\Notifications\\SendQueuedNotifications))
#5 /app/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php(227): Illuminate\\Bus\\Dispatcher->pushCommandToQueue(Object(Illuminate\\Queue\\SyncQueue), Object(Illuminate\\Notifications\\SendQueuedNotifications))
#6 /app/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php(77): Illuminate\\Bus\\Dispatcher->dispatchToQueue(Object(Illuminate\\Notifications\\SendQueuedNotifications))
#7 /app/vendor/laravel/framework/src/Illuminate/Notifications/NotificationSender.php(212): Illuminate\\Bus\\Dispatcher->dispatch(Object(Illuminate\\Notifications\\SendQueuedNotifications))
#8 /app/vendor/laravel/framework/src/Illuminate/Notifications/NotificationSender.php(76): Illuminate\\Notifications\\NotificationSender->queueNotification(Array, Object(App\\Notifications\\SomeMessage))
#9 /app/vendor/laravel/framework/src/Illuminate/Notifications/ChannelManager.php(39): Illuminate\\Notifications\\NotificationSender->send(Array, Object(App\\Notifications\\SomeMessage))
#10 /app/vendor/laravel/framework/src/Illuminate/Notifications/RoutesNotifications.php(18): Illuminate\\Notifications\\ChannelManager->send(Object(App\\DingtalkBot), Object(App\\Notifications\\SomeMessage))
#11 /app/routes/web.php(16): App\\DingtalkBot->notify(Object(App\\Notifications\\SomeMessage))
#12 /app/vendor/laravel/framework/src/Illuminate/Routing/Route.php(230): Illuminate\\Routing\\RouteFileRegistrar->{closure}()
#13 /app/vendor/laravel/framework/src/Illuminate/Routing/Route.php(200): Illuminate\\Routing\\Route->runCallable()
#14 /app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(692): Illuminate\\Routing\\Route->run()
#15 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#16 /app/app/Http/Middleware/CheckAccount.php(55): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#17 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\\Http\\Middleware\\CheckAccount->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#18 /app/app/Http/Middleware/RegisterJPushRegistrationID.php(22): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#19 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\\Http\\Middleware\\RegisterJPushRegistrationID->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#20 /app/app/Http/Middleware/WithTransaction.php(118): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#21 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\\Http\\Middleware\\WithTransaction->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#22 /app/app/Http/Middleware/ImpersonateGuard.php(54): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#23 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\\Http\\Middleware\\ImpersonateGuard->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#24 /app/app/Http/Middleware/SetLocale.php(26): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#25 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\\Http\\Middleware\\SetLocale->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#26 /app/vendor/itsgoingd/clockwork/Clockwork/Support/Laravel/ClockworkMiddleware.php(24): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#27 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Clockwork\\Support\\Laravel\\ClockworkMiddleware->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#28 /app/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(41): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#29 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#30 /app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php(77): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#31 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#32 /app/vendor/laravel/framework/src/Illuminate/Session/Middleware/AuthenticateSession.php(58): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#33 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Session\\Middleware\\AuthenticateSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#34 /app/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(49): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#35 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\View\\Middleware\\ShareErrorsFromSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#36 /app/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(121): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#37 /app/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(63): Illuminate\\Session\\Middleware\\StartSession->handleStatefulRequest(Object(Illuminate\\Http\\Request), Object(Illuminate\\Session\\Store), Object(Closure))
#38 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Session\\Middleware\\StartSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#39 /app/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#40 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#41 /app/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(67): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#42 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Cookie\\Middleware\\EncryptCookies->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#43 /app/app/Http/Middleware/RedirectToAppURL.php(28): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#44 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\\Http\\Middleware\\RedirectToAppURL->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#45 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#46 /app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(694): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
#47 /app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(669): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))
#48 /app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(635): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))
#49 /app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(624): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))
#50 /app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(166): Illuminate\\Routing\\Router->dispatch(Object(Illuminate\\Http\\Request))
#51 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))
#52 /app/vendor/laravel/nova/src/Http/Middleware/ServeNova.php(26): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#53 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Laravel\\Nova\\Http\\Middleware\\ServeNova->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#54 /app/app/Http/Middleware/SentryContext.php(31): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#55 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): App\\Http\\Middleware\\SentryContext->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#56 /app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#57 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#58 /app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#59 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#60 /app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#61 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#62 /app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(87): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#63 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#64 /app/vendor/fruitcake/laravel-cors/src/HandleCors.php(37): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#65 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Fruitcake\\Cors\\HandleCors->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#66 /app/vendor/fideloper/proxy/src/TrustProxies.php(57): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#67 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Fideloper\\Proxy\\TrustProxies->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#68 /app/vendor/itsgoingd/clockwork/Clockwork/Support/Laravel/ClockworkMiddleware.php(24): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#69 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(167): Clockwork\\Support\\Laravel\\ClockworkMiddleware->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#70 /app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#71 /app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(141): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
#72 /app/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(110): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))
#73 /app/public/index.php(52): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))
#74 {main}
"} 
driesvints commented 3 years ago

I think I see what's going on. You're using the framework's Illuminate\Queue\Middleware\RateLimited middleware rather than writing your own as documented here: https://laravel.com/docs/8.x/queues#job-middleware

If you wrote the middleware as documented does the error still happen then?

chuangbo commented 3 years ago

Just dig into #30070, it seems like NotificationSender@queueNotification will assign the result of $notification->middleware() to instance attributes SendQueuedNotifications->$middleware, which contains an instance of RateLimited which created by notification's middleware() method:

    public function middleware()
    {
        return [new RateLimited('notification-channel-xxx')];
    }

The RateLimited instance which contains a named limiter registered in AppServiceProvider. And the named limiter contains a Closure, the root cause stopping SendQueuedNotifications from serialization.

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    RateLimiter::for('notification-channel-xxx', function ($job) {
        return Limit::perMinute(20);
    });
}
driesvints commented 3 years ago

Hmm, I see. I'm not sure what the best solution here would be..

chuangbo commented 3 years ago

Maybe we can retrieve and instantiate middlewares after the job SendQueuedNotifications being unserialized, instead of before the serialization. Or maybe registering the named rate limiters in a non-closure way?

taylorotwell commented 3 years ago

Fixed for PHP 7.4+ by this: https://github.com/laravel/framework/commit/f3d4dcb21dc66824611fdde95c8075b694825bf5

taylorotwell commented 3 years ago

@chuangbo can you confirm the commit above fixes your issue? I see you are on PHP 7.4.

chuangbo commented 3 years ago

@taylorotwell Thank you for the prompt fix! Good to know __serialize and __unserialize. By the way, there is a typo I have it fixed: #35916. It feels great to make a tiny contribution to Laravel. Love your work!

yllndritb commented 3 years ago

I think the same problem is for php 8.x (for me 8.0.6) and Laravel 8.x (for me 8.43.0).