#php #laravel #eloquent
#php #laravel #красноречивый
Вопрос:
В моем контроллере у меня есть функция для проверки статуса подписки и обновления ее в моей базе данных. Проблема в том, что для 50000 пользователей требуется слишком много времени для завершения и тайм-аута.
public function UpdateStatus(){
$users = User::all();
foreach($users as $user){
$user->createOrGetStripeCustomer();
$stripeSubs = $user->asStripeCustomer()->subscriptions->all();
$dbSubs = DB::table('subscriptions')->select('stripe_id')->where('user_id', $user->id)->get();
foreach($dbSubs as $check){
$canDelete=0;
foreach($stripeSubs as $value){
if($check->stripe_id == $value->id){
$canDelete ;
}
}
if($canDelete==0){
DB::table('subscriptions')->where('user_id', $user->id)->where('stripe_id',$check->stripe_id)->update(['stripe_status'=>'ended']);
}
}
}
return redirect('/dashboard');
}
Я уверен, что мне даже не следует обрабатывать столько одновременно, но я как бы застрял здесь и не уверен, как именно подойти к этому. Моя цель — заставить это работать и оптимизировать его.
Комментарии:
1. как насчет того, чтобы сделать это заданием очереди для запуска в фоновом режиме
2. Может быть, chunk() может помочь?
Ответ №1:
вы используете job таким образом:
php artisan make:job checkSubscrption
в вашем env-файле измените Queue_CONNECTiON=database
,
запустите php artisan queue:table
и php artisan migrate
в вашем файле checkSubscription установите, что
public function handle(){
$users = User::all();
foreach($users as $user){
$user->createOrGetStripeCustomer();
$stripeSubs = $user->asStripeCustomer()->subscriptions->all();
$dbSubs = DB::table('subscriptions')->select('stripe_id')->where('user_id', $user->id)->get();
foreach($dbSubs as $check){
$canDelete=0;
foreach($stripeSubs as $value){
if($check->stripe_id == $value->id){
$canDelete ;
}
}
if($canDelete==0){
DB::table('subscriptions')->where('user_id', $user->id)->where('stripe_id',$check->stripe_id)->update(['stripe_status'=>'ended']);
}
}
}}
в вашем контроллере:
public function UpdateStatus(){
checkSubscrption::dispatch();//you can use chunk method and pass your $users as params
return redirect('/dashboard');}
затем запустите php artisan queue:work
Ответ №2:
Во-первых, вы должны сделать это в очередном задании: https://laravel.com/docs/8.x/queues
Таким образом, время ожидания скрипта не истечет.
Однако загрузка 50 тыс. красноречивых объектов в память не является оптимальной. Чтобы решить эту проблему, вы можете использовать отложенные коллекции: https://laravel.com/docs/8.x/collections#lazy-collections
$users = User::cursor();
foreach ($users as $user) {
// do stuff
}
Это выполнит только один запрос, но сохранит в памяти только один User
объект.