Laravel5:如果没有命令准备就绪,如何禁用默认调度程序消息 运行

Laravel5: How to disable default scheduler message if no command is ready to run

使用 Laravel5 scheduler 时:

* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1

如果没有命令准备好 运行,我们会收到以下默认输出:

# No scheduled commands are ready to run.

如何禁用此默认 Laravel5 消息?如果没有准备好 运行 的命令,我们不希望有输出。最好的情况是,当我们能够自己配置该消息和 return 代码时。

您可以在 app/Console/Commands 中创建一个类似于下面的新命令,它扩展了默认的 schedule:run 命令。

它覆盖了 handle 方法,同时保持其他一切不变,以避免 Laravel 在它什么都没做时输出 "No scheduled commands are ready to run." 行。

通过使用不同的名称,无需担心冲突,如果您愿意,您仍然可以随时 运行 原始 php artisan schedule:run 命令。

<?php

namespace App\Console\Commands

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Console\Scheduling\ScheduleRunCommand;

class RunTasks extends ScheduleRunCommand
{
    /**
     * The console command name.
     *
     * @var string
     */
    protected $name = 'run:tasks';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Custom task runner with no default output';

    /**
     * Create a new command instance.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    public function __construct(Schedule $schedule)
    {
        parent::__construct($schedule);
    }

    /**
     * Execute the console command.
     *
     * @return void
     */
    public function handle()
    {
        foreach ($this->schedule->dueEvents($this->laravel) as $event) {
            if (! $event->filtersPass($this->laravel)) {
                continue;
            }
            if ($event->onOneServer) {
                $this->runSingleServerEvent($event);
            } else {
                $this->runEvent($event);
            }
            $this->eventsRan = true;
        }

        if (! $this->eventsRan) {
            // Laravel would output the default text here. You can remove
            // this if statement entirely if you don't want output.
            //
            // Alternatively, define some custom output with:
            // $this->info("My custom 'nothing ran' message");
        }
    }
}

验证 Laravel 是否看到您的新命令:

php artisan | grep run:tasks

最后将您的 cron 更新为 运行 新命令:

* * * * * cd /path-to-your-project && php artisan run:tasks >> /dev/null 2>&1

正如我在评论中提到的,我看到了两种可能性

您可以删除不需要的内容

* * * * * cd /path-to-your-project && php artisan schedule:run | awk '{ if (/No scheduled commands are ready to run./ && !seen) { seen = 1 } else print }'

或者您可以使用自己的命令覆盖:

$ php artisan make:command ScheduleRunCommand

通过创建您自己的命令(主要是来自 ScheduleRunCommand 的 copy/past) 或按照@dave-s 的建议扩展 ScheduleRunCommand

如果您还想 运行 php artisan schedule:run 使用您的新命令, 您需要在服务提供商中注册它

$this->app->extend('schedule.run', function () {
    return new \App\Console\Commands\ScheduleRunCommand;
});

如果您在 https://github.com/laravel/framework/blob/78505345f2a34b865a980cefbd103d8eb839eedf/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php#L82

查看 Laravel 的代码
public function handle()
{
    foreach ($this->schedule->dueEvents($this->laravel) as $event) {
        if (! $event->filtersPass($this->laravel)) {
            continue;
        }
        if ($event->onOneServer) {
            $this->runSingleServerEvent($event);
        } else {
            $this->runEvent($event);
        }
        $this->eventsRan = true;
    }
    if (! $this->eventsRan) {
        $this->info('No scheduled commands are ready to run.');
    }
}

您看到它是通过 $this->info 处理程序处理的。

信息处理程序在 Command.php Which calls the line method, which calls the output handler which is defined in the run command

中定义

所以本质上,为了能够拦截它,您应该能够通过在 运行 您在 cron 作业中调用的文件中的命令之前绑定自己的输出处理程序来覆盖 OutputStyle which is based on the symfonystyle

我能想到的最佳工作方案是使用 OutputFormatter,当字符串与目标字符串匹配时,您只需 return null。

 $this->output->setFormatter( new MyCatchemAllFormatter() );

并且在 class 中,您将定义如下内容:

use Symfony\Component\Console\Formatter\OutputFormatter;

class MyCatchemAllFormatter extends OutputFormatter 
{
    public function formatAndWrap(string $message, int $width) 
    {
        if($message != 'No scheduled commands are ready to run.') {
             return parent::formatAndWrap($message, $width);
        }
        return null;
    }
}

I understand that my solution is DIRTY and I'll get downvotes by most of SO users, but it's quick to do without registering additional service providers, modifying classes and etc.

我检查了来源并在 ScheduleRunCommand81 行找到了 this,即

public function handle()
{
    foreach ($this->schedule->dueEvents($this->laravel) as $event) {
        if (! $event->filtersPass($this->laravel)) {
            continue;
        }
        if ($event->onOneServer) {
            $this->runSingleServerEvent($event);
        } else {
            $this->runEvent($event);
        }
        $this->eventsRan = true;
    }
    if (! $this->eventsRan) { // L81
        $this->info('No scheduled commands are ready to run.'); // L82
    }
}

使用它 "cheat" 的最快方法是将 class 复制到 app/Console/ScheduleRunCommand.php 并在每次调用 composer dump-autoload 时将该文件复制到原始源路径。

1) 将原始文件复制到 app/Console 文件夹:

cp vendor/laravel/framework/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php patch/ScheduleRunCommand.php app/Console/ScheduleRunCommand.php

2) 在 composer.json scripts:post-autoload-dump 部分添加这样的行:

cp app/Console/ScheduleRunCommand.php vendor/laravel/framework/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php

3) 修改您在 app/Console/ScheduleRunCommand.php (L82) 中的消息:

if (! $this->eventsRan) {
    $this->info('NOTHING');
}

4) 运行: composer dump

结果: