Запрос на элегантное решение Собираюсь переделать существующие регулярные задачи с crontab на ларавелевский Task Scheduling — чтобы всё было под контролем git. Почитал, попробовал, в целом нравится. Хочу посоветоваться насчет рассылки результатов. В кротаб это выглядит примерно так: Код (Text): MAILTO="sasha@example.com,petya@example.com" */10 * * * * php /path/to/task_a.php */20 * * * * php /path/to/task_b.php MAILTO="petya@example.com" 0 17 * * * php /path/to/task_c.php MAILTO="olga@example.com" 0 20 * * * php /path/to/task_d.php То есть sasha получает сообщения про a и b. petya - a, b и c. olga - d. Хочу повторить подобное для Kernel::schedule(). Есть нюанс: сами задачи и расписание надо держать под version control, а вот списки извещения настраивать независимо, то есть через dotenv. Почту не хардкодить! Сходу получется что-то вроде этого, корявенько: PHP: $schedule->command('foo:bar') ->everyTenMinutes() ->emailOutputTo(env('LIST_FOO_BAR')); В моём понимании элегантно было бы вообще избавиться от явного упоминания emailOutputTo(), а использовать какие-то события за кадром и в .env типа Код (Text): LIST_FOO_BAR="sasha@example.com,petya@example.com" LIST_BAR_BAZ="olga@example.com" И так как же мне повесить событие на command и сделать магию с "foo:bar" => "LIST_FOO_BAR" ?
Найдёшь, отпишись плиз. Буду следить за этой темой, но сейчас специально в исходниках покопался, ничего похожего на глобальные события после выполнения команды в исходнике не нашёл. И \Illuminate\Console\Scheduling\Event создаётся не через DI-контейнер, так что его не отдекорировать...
Так, давай по порядку ) Почему бы не оформить таски как консольные команды и не передавать данные опциями / аргументами? Ну или как-то так к примеру: Код (Text): $ FOO=bar php -r "echo getenv('FOO').PHP_EOL;" bar
Кто хочет узнать больше о ларавелевском шедулинге, вот есть по русски: https://laravel.ru/docs/v5/scheduling Почитайте, потом просветлённые возвращайтесь к вопросу этой темы.
Канонично: Создавая класс команды, ты можешь свойством описать сигнатуру: PHP: protected $signature = 'email:send {user} {--queue=}'; И потом обратиться к переданным параметрам PHP: $queueName = $this->option('queue'); $user = $this->getArgument('user'); Ну и вызвать их с нужными данными PHP: $schedule->command('emails:send username --force=value')->daily(); Второй вариант, если тебе принципиально надо передавать через переменные окружения, то ты можешь их передать вместе с вызовом скрипта Код (Text): FOO=bar /path/to/php script.php В результате скрипт её увидит. Конкретно твой пример будет выглядеть так: PHP: $schedule->exec('MAILTO="olga@example.com" php /path/to/task_d.php')->cron('0 20 * * *'); p.s. ну или это я не понял вопроса ))
Да, походу ты не понял вопроса. Кажется ты не в курсе как кронтаб шлёт письма. Он сам шлёт письма, а не выполняемая из него команда. Такое вот разделение обязанностей Рассказываю анекдот снова: возьмём за основу это PHP: class Kernel extends ConsoleKernel { protected function schedule(Schedule $schedule) { $schedule->command('foo:bar') ->everyTenMinutes() ->emailOutputTo(env('LIST_FOO_BAR')); $schedule->command('bar:baz') ->dailyAt('18:00') ->emailOutputTo(env('LIST_BAR_BAZ')); // Таких записей будет десяток-другой // . . . } } А в настоящем кроне будет ежеминутно стартовать php /path/to/artisan schedule:run То, что выше уже должно работать. Но… Давай будем считать, что вывод каждой команды в расписании должен отсылается на почту. Конкретные емайлы вбивать в код нельзя. Хочется чтобы привязка команд к адресам прописывалась отдельно, скорее всего в .env. Потому как это вещь изменчивая и server dependent. Попытаемся добавить сахарку: избавиться от явного упоминания env() и явного упоминания emailOutputTo(). Ибо когда строк много, это выглядит как мусор. Рабочая идея такая: использовать свой унаследованный класс Schedule, который бы декорировал command(). Но рассмотрю иные варианты. То что ты @romach выше писал это просто мимо.
Отчитываюсь. Завел такое правило для адресов рассылки: в .env описывается адрес по-умолчанию и опционально адреса, соответствующие командам: Код (Text): SCHEDULE_MAILTO=webmaster@example.com # for "dummy:output" command SCHEDULE_DUMMY_OUTPUT_MAILTO=sasha@example.com,petya@example.com # for "slack:send" SCHEDULE_SLACK_SEND_MAILTO=petya@example.com В Kernel::schedule() добавил замыкание, которое вычисляет адрес и даёт задание на отправку почты: PHP: protected function schedule(Schedule $schedule) { $defaultEmail = env('SCHEDULE_MAILTO'); $run = function($command) use($schedule, $defaultEmail) { // Initialize event then, if email address is set, send report $event = $schedule->command($command)->description($command); $name = str_replace(':', '_', strtoupper(explode(' ', $command)[0])); return ($email = env("SCHEDULE_{$name}_MAILTO", $defaultEmail)) ? $event->emailOutputTo(explode(',', $email), true) : $event; }; $run('dummy:output')->everyFiveMinutes(); $run('env')->hourly(); // ... $run ... $run ... $run } в этом примере для команды "dummy:output" будет найден специфичный адрес, а для "env" будет использован адрес по умолчанию. если адрес по умолчанию также не задан, то рассылки не будет пустые письма также не шлём, emailOutputTo($addresses, true) — второй аргумент говорит о том, что почту надо отправлять только если вывод команды непустой (как в кроне) Вроде получилось как хотел. Предложения приветствуются.
@artoodetoo херасе ты от двух строчек избавился )) Дык вот, если говорить о каноне и элегантности, то сообщения шлются по средством Notifications. Т.е. создается сущность, которая принимает некоторый набор данных и исходя из него шлет что надо и кому надо в нужном виде. Само же событие, как следует из названия должно пройти через Events. Кратко: команда что-то делает, собирает и генерирует событие, по результату которого уже и стартует Notification с переданными по цепочке данными и отправляющий всё это на нужные каналы. Бонусом ты получаешь возможность гибко управлять логикой всего этого: на определенную почту, конкретному юзеру, в слак или широковещательно всем онлайн пользователям разом. Ну и не нагружаешь крон логикой, которая явно к нему не относится )
@romach кто против, так это не я. покажи как можно "гибко управлять логикой". повторю условия: есть консольные команды. мы можем вызвать любую из них с командной строки как `php artisan command:name parameters` при этом команда что-то выводит в консоль чтобы я видел как оно проистекает. если эту же команду выполняем по расписанию, то конечно вывод я не увижу, если только я не пропишу свой адрес в список оповещения (не в исходниках). вот вся задача: в одном случае не надо писем, в другом надо. и желательно сделать просто и без дублирования.