Настройка и тестирование планирования задач Laravel

окружающая среда

  • Фреймворк Laravel Версия : 5.1.45 (LTS)

  • версия PHP : 5.6.1


описание

Я пытаюсь запустить команду каждые 1 минуту с помощью Laravel Планирование Задач.


попытка

я добавил эту строку в файл вкладки cron

* * * * * php artisan schedule:run >> /dev/null 2>&1

вот мой / app / консоль / ядро.в PHP

<?php

namespace AppConsole;

use IlluminateConsoleSchedulingSchedule;
use IlluminateFoundationConsoleKernel as ConsoleKernel;

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

    /**
     * Define the application's command schedule.
     *
     * @param  IlluminateConsoleSchedulingSchedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        $schedule->command('inspire')->hourly();
        $schedule->command('echo "Happy New Year!" ')->everyMinute(); //<---- ADD HERE        }
}

я добавил эту строку $schedule->command('echo "Happy New Year!" ')->everyMinute();


вопрос

как это проверить ?

как вызвать мое Эхо для отображения ?

откуда мне знать, если я не ошибаюсь ?


Я открываю для любых предложений в этот момент.

любые подсказки / предложения / помощь по этому вопросу будут высоко оценены !

3 ответов


command() запускает команду ремесленника. То, что вы пытаетесь достичь - выдача команды ОС - выполняется exec('echo "Happy New Year!"')

тестирование зависит от того, что вы хотите проверить:

  • работает ли планировщик (каждую минуту)?

в этом случае, вам не придется. Он тестируется в исходном рамочном коде.

  • успешно ли выполняется команда?

Ну, вы можете вручную запустить php artisan schedule:run и видим выход.

планировщик не производит никаких выходных данных по умолчанию (>> /dev/null 2>&1). Однако вы можете перенаправить вывод запущенных скриптов в любой файл, связав writeOutputTo() или appendOutputTo() (https://laravel.com/docs/5.1/scheduling#task-output).


для более сложной логики вместо этого напишите консольную команду (https://laravel.com/docs/5.1/artisan#writing-commands) и использовать command() - таким образом, вы можете написать хороший, проверяемых код.


Если вы хотите модульное тестирование планирования событий, вы можете использовать этот пример. Он основан на команде inspire по умолчанию:

public function testIsAvailableInTheScheduler()
{
    /** @var \Illuminate\Console\Scheduling\Schedule $schedule */
    $schedule = app()->make(\Illuminate\Console\Scheduling\Schedule::class);

    $events = collect($schedule->events())->filter(function (\Illuminate\Console\Scheduling\Event $event) {
        return stripos($event->command, 'YourCommandHere');
    });

    if ($events->count() == 0) {
        $this->fail('No events found');
    }

    $events->each(function (\Illuminate\Console\Scheduling\Event $event) {
        // This example is for hourly commands.
        $this->assertEquals('0 * * * * *', $event->expression);
    });
}

основываясь на ответе Михила, я использовал методы, содержащиеся в Illuminate\Console\Scheduling\Event чтобы проверить, должно ли событие выполняться в течение заданной даты.

Я высмеял текущую дату, используя Carbon::setTestNow() Так что любая логика на основе даты в when() и skip() фильтры будут вести себя, как ожидалось.

use Tests\TestCase;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Console\Scheduling\Event;

use Cron\CronExpression;
use Carbon\Carbon;


class ScheduleTest extends TestCase {


    public function testCompanyFeedbackSchedule()
    {
        $event = $this->getCommandEvent('your-command-signature');

        $test_date = Carbon::now()->startOfDay()->addHours(8);

        for ($i=0; $i < 356; $i++) { 
            $test_date->addDay();
            Carbon::setTestNow($test_date);

            // Run the when() & skip() filters
            $filters_pass = $event->filtersPass($this->app);
            // Test that the Cron expression passes
            $date_passes = $this->isEventDue($event);
            $will_run = $filters_pass && $date_passes;

            // Should only run on first friday of month
            if ($test_date->format('l') === 'Friday' && $test_date->weekOfMonth === 1) {
                $this->assertTrue($will_run, 'Task should run on '. $test_date->toDateTimeString());
            } else {
                $this->assertFalse($will_run, 'Task should not run on '. $test_date->toDateTimeString());
            }
        }
    }


    /**
     * Get the event matching the given command signature from the scheduler
     * 
     * @param  string  $command_signature
     * 
     * @return Illuminate\Console\Scheduling\Event
     */
    private function getCommandEvent($command_signature)
    {
        $schedule = app()->make(Schedule::class);

        $event = collect($schedule->events())->first(function (Event $event) use ($command_signature) {
            return stripos($event->command, $command_signature);
        });

        if (!$event) {
            $this->fail('Event for '. $command_signature .' not found');
        }

        return $event;
    }


    /**
     * Determine if the Cron expression passes.
     * 
     * Copied from the protected method Illuminate\Console\Scheduling\Event@isEventDue
     * 
     * @return bool
     */
    private function isEventDue(Event $event)
    {
        $date = Carbon::now();

        if ($event->timezone) {
            $date->setTimezone($event->timezone);
        }

        return CronExpression::factory($event->expression)->isDue($date->toDateTimeString());
    }
}