Mohamad Karimisalim
Mohamad Karimisalim

Reputation: 170

How to run command in Laravel kernel after another successful command

I'm creating a custom command which will truncate a table every thirty minutes in the console kernel (for development purposes). I want to run another right after the previous command.

P.S: I have an if statement which prevents running these commands on the production server.

$schedule->command('db:seed')->after(function () use ($schedule) : void {
    $schedule->command('my-command:remove-users-from-tables')
        ->everyThirtyMinutes()
        ->environments(['demo', 'local']);
});

I expect to run the seeder right after "my-command" runs successfully every thirty minutes. However, in this way, only db:seed runs.

Upvotes: 4

Views: 5153

Answers (4)

Alexey Burdin
Alexey Burdin

Reputation: 132

The OP approach doesn't run the second command even in laravel 11, I'll try to explain why.
The whole class \Illuminate\Console\Scheduling\Schedule (which is, btw, referenced in \App\Console\Kernel::schedule as the parameter) is dedicated to only put the commands into \Illuminate\Console\Scheduling\Schedule::events property, and not more.
Commands like schedule:run (\Illuminate\Console\Scheduling\ScheduleRunCommand::handle) or schedule:list fetch the "events" only once,
so, when one add an event to Schedule::events after the fetch, the "events" aren't queried after that at all, alone to say run.

It is suggested to make a job, consisting of the only Artisan::call command and run it with dispatch in the after method parameter closure of the schedule builder.

Upvotes: 0

mwallisch
mwallisch

Reputation: 1810

If you want to run B after A you need to schedule A and AFTER that run B:

$schedule->command('my-command:remove-users-from-tables')
        ->everyThirtyMinutes()
        ->after(function() {
            $this->artisan->call('db:seed');
        });

Upvotes: 2

Abraham Brookes
Abraham Brookes

Reputation: 1998

An alternative that may be relevant in some cases (but I can imagine would also be a bad idea in others) is to run shell_exec: https://www.php.net/manual/en/function.shell-exec.php

If you want to chain two artisan commands together as you would on the cli using && you can simply shell_exec('php artisan command:first && php artisan command:second').

shell_exec returns the console output so if your commands print anything (ie, via $this->info) then you can print that to console like so: $this->info(shell_exec('php artisan command:first && php artisan command:second'))

I'm probably going to get a lot of hate for this answer...

Upvotes: 1

Kevin Bui
Kevin Bui

Reputation: 3045

I have checked the source code for Illuminate\Console\Scheduling\Schedule class.

I think when we say:

$schedule->command(...);

The artisan command will be scheduled, not run straightaway.

So when you write like this:

$schedule->command('first-command')->after(function () use ($schedule) {
    $schedule->command('second-command');
});

The second command will be registered, not run right after the first command.

So the best approach that I can think of is run the second command inside the first command according to this link

You might try something like this:

namespace App\Console\Commands;

use Illuminate\Console\Command;

class RemoveUsersFromTable extends Command
{
    public function handle()
    {
        // Do something to remove users from table.

        $this->call('db:seed');
    }
} 

Upvotes: 3

Related Questions