Home > Net >  Command times out when executing
Command times out when executing

Time:02-14

Laravel version:
8.x

PHP version:
8.0

MySQL version:
8.0

Server:
Larave Forge

I'm running a command on one of my websites

php artisan command:here

after a few minutes I get this status "Timed Out", is there anything that can be optimized here to prevent the time out?

subscriptions table has 40,000 records and incomes table has 8,000,000. Every subscription has a maximum of 200 records in the incomes table.

To explain what this command does, this is fixing (by inserting) the lacking of income of every ACTIVE subscription, which will be identified based on the hour difference from the last income that has been inserted. Every subscription has a max of 200 records in the incomes table, so if the script detected that a subscription has already reached the 200 income records, it will update the status to COMPLETED.

Subscription.php (model)

public function latestIncome()
{
    return $this->hasOne(Income::class)->latestOfMany();
}

Income.php (model)

public function subscription()
{
    return $this->belongsTo(Subscription::class);
}
namespace App\Console\Commands;

class SomeCommand extends Command
{
    protected $signature = 'command:here';

    public function handle()
    {
        ini_set('max_execution_time', 0);

        foreach (Subscription::with('latestIncome')->withCount('income')->where('status', 'ACTIVE')->lazy() as $subscription) {
            $count_earnings = $subscription->income_count;
            $recent_bonus = $subscription->latestIncome;

            if ($recent_bonus) {
                if ($count_earnings < 200) {
                    $hour_difference = now()->diffInHours($recent_bonus->created_at);

                    if ($hour_difference > 1) {
                        $to_insert = 200 - $count_earnings;
                        $max = $hour_difference;

                        if ($hour_difference > $to_insert) {
                            $max = $to_insert;
                        }

                        for ($i = 0; $i < $max; $i  ) {
                            $income = new Income;
                            $income->user_id = $subscription->user_id;
                            $income->subscription_id = $subscription->id;
                            $income->amount = (100 * 0.002) * 100;
                            $income->save();
                        }

                        if (($count_earnings   $max) >= 200) {
                            $subscription->update(['status' => 'COMPLETED']);
                        }

                        Log::info('Fix for:'.$subscription->id.' | User:'.$subscription->user_id.' | Total:'.$max);
                    }
                } else {
                    $subscription->update(['status' => 'COMPLETED']);
                }
            }
        }
    }
}

CodePudding user response:

You can define a time limit in the __construct function or in your index controller if you want a large time restriction.

    public function __construct()
    {
        set_time_limit(8000000);
    }

CodePudding user response:

You might gain some performance if you do your updates in bulk:

namespace App\Console\Commands;

class SomeCommand extends Command
{
    protected $signature = 'command:here';

    public function handle()
    {
        ini_set('max_execution_time', 0);

        // Update everything you can before the loop
        Subscription::has('income', '>=', 200)
                ->where('status', '!=' 'COMPLETED')
                ->update([ 'status' => 'COMPLETED' ]);

        foreach (Subscription::with('latestIncome')->withCount('income')->where('status', 'ACTIVE')->lazy() as $subscription) {
            $count_earnings = $subscription->income_count;
            $recent_bonus = $subscription->latestIncome;

            if ($recent_bonus) {
              $hour_difference = now()->diffInHours($recent_bonus->created_at);

              if ($hour_difference > 1) {
                   $to_insert = 200 - $count_earnings;
                   $max = $hour_difference;

                   if ($hour_difference > $to_insert) {
                       $max = $to_insert;
                   }
                        
                   // Some performance gain here possibly
                   Income::insert(collect()->pad($max, [ 
                         'user_id' => $subscription->user_id,
                         'subscription_id' => $subscription->id,
                         'amount' => (100 * 0.002) * 100,
                   ])->all());

                   Log::info('Fix for:'.$subscription->id.' | User:'.$subscription->user_id.' | Total:'.$max);
                }
            }
        }
       // Update anything that got pushed over that threshold
       Subscription::has('income', '>=', 200)
            ->where('status', '!=' 'COMPLETED')
            ->update([ 'status' => 'COMPLETED' ]);
    }
}

  • Related