Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

amitshahc's avatar

Custom command running directly from CLI but not from schedule:run in CLI

My OS is Windows 7 : Laravel 5.8

Some how I also found the same issue and tried everything listed here but no solution yet. I am using Laravel 5.8 and when i run the command from my windows cmd using

php artisan subscription:fallback it's running and i can verify the entries in the database which been created by that job.

But the same command is not executing when i call php artisan schedule:run it prints the messages in before() and after() hooks plus sending the email but with blank content. but no code being executed inside the handle() method.

myLaravelProject >php artisan schedule:run
Running scheduled command: "D:\Installation\php7114\php.exe" "artisan" inspire >> "D:\Installation\Apache24\htdocs\spaadvisor.com\storage\logs/schedule/2019-08-29.log" 2>&1
Running scheduled command: "D:\Installation\php7114\php.exe" "artisan" subscriptions:fallback 2 --force >> "D:\Installation\Apache24\htdocs\spaadvisor.com\storage\logs/schedule/2019-08-29.log" 2>&1
subscriptions:fallback command is started..
Finished.!

FreeSubscriptionFallback:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Modules\SuperAdmin\Entities\Repository\Contract\CronjobRepository;

class FreeSubscriptionFallback extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'subscriptions:fallback {days=2: number of max days from today to calculate expiry date range}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Auto renewal of shop-owner\'s subscriptions to Free for which are expiring within next {days=2} days';

    /**
     * Create a new command instance.
     *
     * @return void
     */

    protected $repo;

    public function __construct(CronjobRepository $repo)
    {
        parent::__construct();
        $this->repo = $repo;
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $this->info('Subscription fallback command logic : STARTED');
        // dd('hello');
        $days       = (int) $this->argument('days');
        $shopowners = $this->repo->getActiveSubscriptions($days);
        // dd($shopowners);
        try {
            $shopowners->each(function ($shopowner) {
                $this->line('Creating default subscription for shopowner id:', $shopowner->id);
                $this->repo->beginTransaction();
                $this->repo->createSubscription_default($shopowner);
                $this->repo->commit();
            });

            $this->info('Subscription fallback command logic : ENDED');

        } catch (\Throwable $th) {
            $this->repo->rollback();
            $this->error('Subscription fallback command logic : ERROR', $th);
            report($th);
        }
    }
}

Kernel.php:

<?php

namespace App\Console;

use Artisan;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use Modules\SuperAdmin\Jobs\SubscriptionRenewal;
use Modules\SuperAdmin\Entities\Repository\Contract\CronjobRepository;

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        \App\Console\Commands\FreeSubscriptionFallback::class,
    ];

    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        // $schedule->command('inspire')
        //          ->hourly();
        $today    = \DateTimeOperations::today()->toDateString();
        $logfile  = config('constants.scheduler.logfile_path') . $today . '.log'; //storage_path("logs/schedule/". $today .".log");
        $cronRepo = resolve(CronjobRepository::class);

        $schedule->job(new SubscriptionRenewal($cronRepo))->daily()
            ->before(function () {
                echo "SubscriptionRenewal job is started..\n";
            })
            ->after(function () {
                echo "Databse queue is started..\n";
                echo $exitCode = Artisan::call('queue:work database --stop-when-empty');
                echo "Finished.!\n";
                echo Artisan::output();
            })
            ->appendOutputTo($logfile)
            ->emailOutputTo(config('constants.scheduler.report_email'));

        $schedule->command("inspire")->everyMinute()
            ->appendOutputTo($logfile)
            ->emailOutputTo(config('constants.scheduler.report_email'));

        $schedule->command("subscriptions:fallback 2 --force")->everyMinute()
            ->before(function () {
                echo "subscriptions:fallback command is started..\n";
            })
            ->after(function () {
                echo "Finished.!\n";
                // echo Artisan::output();
            })
            ->onSuccess(function () {
                echo "Success";
            })
            ->onFailure(function () {
                echo "Failed";
            })
            ->appendOutputTo($logfile)
            ->emailOutputTo(config('constants.scheduler.report_email'));
        // echo Artisan::output();
    }

    /**
     * Register the commands for the application.
     *
     * @return void
     */
    protected function commands()
    {
        $this->load(__DIR__ . '/Commands');

        require base_path('routes/console.php');
    }
}

After adding ->onFailure() in above i realized that it's printing Failed but no logs anywhere can be found (email, logfile, laravel log, catch..) So how to print the Failure reason?

0 likes
3 replies
amitshahc's avatar
amitshahc
OP
Best Answer
Level 2

SOLVED

For those who are failing without having any error logs anywhere make sure this things first. In my case there were a combinations of the reasons.

  1. The "--force" option does not exist remove any options that do not support your custom command and try to run it independent.
  2. This was the most important change: the $logfile path was inside /storage/logs/schedule/today.log so i was expecting that the schedule sub directory will be getting created by its own like a normal behavior. but i was wrong either keep the log file path directly in to /storage/logs/ or create/keep the sub directory /schedule/ being existed before running this command.
amitshahc's avatar

New issue of execution order

I refactored my Kernel.php as follows:

<?php

namespace App\Console;

use Artisan;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use Modules\SuperAdmin\Entities\Repository\Contract\CronjobRepository;
use Modules\SuperAdmin\Jobs\SubscriptionRenewal;

class Kernel extends ConsoleKernel
{
    protected $repo;
    protected $logfile;
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        \App\Console\Commands\FreeSubscriptionFallback::class,
    ];

    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        $today         = \DateTimeOperations::today()->toDateString();
        $this->logfile = config('constants.scheduler.logfile_path') . $today . '.log';
        $this->repo    = resolve(CronjobRepository::class);

        $this->_renewalNotificationJob($schedule);
        $this->_subscriptionFallback($schedule);

        $schedule->command("inspire")->everyMinute()
        // ->appendOutputTo($logfile)
            ->emailOutputTo(config('constants.scheduler.report_email'));

    }

    /**
     * Register the commands for the application.
     *
     * @return void
     */
    protected function commands()
    {
        $this->load(__DIR__ . '/Commands');

        require base_path('routes/console.php');
    }

    private function _renewalNotificationJob(&$schedule)
    {
        $schedule->job(new SubscriptionRenewal($this->repo))->everyMinute() //daily()
            ->before(function () {
                echo "SubscriptionRenewal job is started..\n";
            })
            ->after(function () {
                echo "Databse queue is started..\n";
                echo $exitCode = Artisan::call('queue:work database --stop-when-empty');
                echo "Finished.!\n";
                echo Artisan::output();
            })
        // ->withoutOverlapping()
            ->appendOutputTo($this->logfile)
            ->emailOutputTo(config('constants.scheduler.report_email'));
    }

    private function _subscriptionFallback(&$schedule)
    {
        $schedule->command("subscriptions:fallback 2")->everyMinute()
            ->before(function () {
                echo "subscriptions:fallback command is started..\n";
            })
            ->after(function () {
                echo "Finished.!\n";
            })
            ->onSuccess(function () {
                echo "Success\n";
            })
            ->onFailure(function () {
                echo "Failed\n";
            })
        // ->withoutOverlapping()
            ->appendOutputTo($this->logfile)
            ->emailOutputTo(config('constants.scheduler.report_email'));
    }
}

The issue is if i run the job first then no more command are being executed.

$this->_renewalNotificationJob($schedule);
$this->_subscriptionFallback($schedule);

but if i run all the command first and job at last, then everything is being executed.


        $this->_subscriptionFallback($schedule);

        $schedule->command("inspire")->everyMinute()
            ->appendOutputTo($this->logfile)
            ->emailOutputTo(config('constants.scheduler.report_email'));
        
        $this->_renewalNotificationJob($schedule);

The moral of the story is $schedule->job stops further execution.

rajiv's avatar

Also check for storage folder permission issues.

Please or to participate in this conversation.