Комментарии 32
1. Для запуска судя по всему нужно чтоб скрипт дернуло что-то внешнее (http-запрос или cron)? Если да то вылезает минус с ресурсоемкими задачами — придется ждать пока они завершаться (беглый взгляд не увидел асинхронности)
2. Не смотрели в сторону https://github.com/Cron/Cron?
3. Пространство имен Scheduler — было бы неплохо добавить имя вендора
4. Не думали сделать что-то типа такого?
Да, в начале статьи я упомянул что необходимо иметь один cron job для запуска. Асинхронность или контроль за тем, чтобы не запускались новые процессы пока не завершился предыдущий подразумевается делать на высшем уровне, т.е. там где будет кофигурироваться и запускаться библиотека.
Изначальная идея была в использовании формата iCalendar, который позволяет куда более гибкую конфигурацию графиков выполнения.
Делать UI для этой библиотеки не планировалось. На мой взгляд это не лучшая практика. Такие вещи должны быть скрыты от пользователя и не должны управляться через GUI.
В итоге получилось бы или как в последнем примере или как здесь.
Ну или можно было бы вообще отвязаться от крона и использовать https://github.com/amphp/amp, ориентироваться на этот кусок, но это привнесет кучу других проблем с проверкой состояния демона, разруливания по отдельным процессам и т.п.
Вы можете элементарно обернуть запуск JobRunner'а, если вам хочется запускать его при помощи демона. Следуя примеру который вы привели это примерно 10-15 строк кода.
1. Как вы будите мониторить работают ли сейчас ваши джобы, и как вы поймете какую из завсших надо прибить, ну малоли
2. Как мониторить включены не включены конкретные джобы?
3. Как быть с консьюмерами?
Основная задаче не только раскатать и абы как запустить, а замониторить, что все работает как планировалось, а не как придется. И в случае падения и ошибок видеть это в Zabbix, Graylog, etc.
Для моих целей необходима была реализация на PHP, чтобы сделать ее независимой от посторонних инструментов, сделать ее частью проекта, а сами job'ы сделать частью его конфигурации. Например так же как конфигурируется роутер различных CMS и фреймворков.
Можно бесконечно развивать и прикручивать к нему все что придет в голову. Логгирование, мониторинг, многопоточность и GUI. Только на мой взгляд это зона ответственности других инструментов. У меня нет желания лепить монструозную библиотеку. Данная реализация предоставляет необходимое API, чтобы вы могли заставить их работать с любым другим инструментом для любых ваших целей.
Правильно понимаю, что любой fatal error тихо положит планировщик со всеми задачами на неопределенном этапе выполнения?
Контроля запуска дубликатов тоже не увидел.
Насколько помню, такой велосипед (раз уж есть доступ до cron-a) реализовывался ранее всегда через демон-подобный вечный скрипт с pid.lock файлом для контроля запуска дублей, полной обработкой всех ошибок, чтобы жить как можно дольше или предсказуемо падать при первой возможности, а также реакцией на принудительное завершение через sig9 — в друпале, джумле, вордпрессе и пр.
Нет четкого разделения ответственности: за дубликаты задач должны отвечать сами задачи, но в то же время ваш планировщик зачем-то хранит в памяти кучу вывода из этих самых задач. В таком вопросе обычно либо все, либо ничего — нужно четко определять границы обслуживания, иначе либо задача пишется, подразумевая использование именного вашего планировщика (отсутствует эффект drop-in replacement), либо допиливать каждый раз через обертки ваш интерфейс, что делает продукт менее интересным.
Если в вашем приложении появляется fatal error, то у меня для вас плохие новости.
По существу fatal error должен появляться в вашем приложении не чаще чем никогда. Но если у вас другое мнение, то register_shutdown_function вам в помощь. Обработка fatal error далеко не зона ответственности этой библиотеки.
Зона ответственности планировщика — выполнять задания по плану гарантированно и предсказуемо (без неоднозначности).
Вопрос: если одно из заданий "рушится" — а это ожидаемое с некоторой долей вероятности (в зависимости от заявленного качества ПО в соответствии с ISO 9000, раз уж мы тут про "по существу") — планировщик может гарантировать, что не упадет сам и выполнит следующее в очереди задание, независимо от "результатов" предыдущего?
Если все-таки он рушится вместе с заданием, откуда он начнет выполнение заданий со следующим запуском: с начала или с момента аварийной остановки?
Что случится при запуске двух и более копий планировщика?
У нас несколько разный взгляд на разработку ПО. Я полагаю, что fatal error и "обрушение" недопустимы, и закладывать их вероятность при разработке это дикость. Представьте строителей, которые закладывают вероятность обрушения потолка при строительстве: "а давайте его веревками к стропилам привяжем, вдруг обрушится" (хотя, кажется, теперь я знаю чем руководствуются разработчики Skype).
Если говорить об ожидаемых авариях, исключительных ситуациях (Exceptions), то JobRunner их ловит, являясь последним форпостом на пути брошенного Exception. Но не пойманные исключения тем приложением, которое их бросило — тоже отдельный вопрос, который также не лучшим образом характеризует качество кода. Я долго сомневался стоит ли вовсе ловить исключения, брошенные чужим кодом.
Что касается запуска двух копий, тут я с вами согласен. В некоторых обстоятельствах может возникнуть такая ситуация (хотя ее тоже можно обработать кодом, запускающим планировщик). Но у меня в планах реализовать параллельное выполнение нескольких JobRunner.
закладывать их вероятность при разработке это дикость
Это не дикость, а выбор паттерна поведения в случае непредвиденной реакции окружения ("обрушилась" база, подключение, недостаточно памяти, не был получен семафор и т.д.). В том числе выход из процедуры с ошибкой, завершение приложения с кодом ошибки и проч — такое встречается повсеместно, а в некоторых системах "обрушение" и вовсе приветствуется, как гарантированная остановка приложения — все зависит от целей, бизнес-процесса, принятых норм, а также соответствия уровню качества (доверия), который был выбран, исходя из целей по рентабельности кода, а также всей системы, частью которой эта Job является.
"а давайте его веревками к стропилам привяжем, вдруг обрушится"
Холодное и горячее резервирование систем вам чуждо, я так полагаю.
Простейшее решение в виде запуска задачи в независимом/слабозависимом потоке легко решит вопрос и сделает логику планировщика предсказуемой в этой части.
Простейшее решение — указать callback для Job'а, который запустит ваш код в независимом потоке, на удаленном worker сервере или где вам угодно с необходимыми вам Fault tolerance, Graceful degradation, обработкой "падений", бэкапами и прочим.
Обработка ошибок стороннего кода и "падений" сторонних сервисов — не область ответственности этой библиотеки.
Я говорю не об обработке ошибок, а о том, чтобы ваш планировщик не падал из-за критической ошибки в запускаемой задаче, оставаясь независимым предсказуемым участником системы
Я понимаю о чем вы. Возможно я добавлю другую реализацию ActionInterface
, которая будет запускать задачу в отдельном процессе.
Более того, я считаю что для библиотеки Cron менеджера просто недопустимы вот такие вещи:
При запуске планировщика при помощи cron я советую сохранять время последнего запуска, и при следующем запуске передавать его в параметр $from прибавив одну секунду, так как точность cron'а не идеальна, и существует вероятность пропустить какие-либо задачи или выполнить их дважды.
Как итог оставлю свое личное мнение — библиотека написана красиво и качественно, но к сожалению едва-ли применима как полноценный CronManager.
Симпатично написано. Надо будет подумать, и попробовать написать обертку для yii. Спасибо.
Но использование стандарта iCalendar было одной из основных целей написания этой библиотеки. Он гораздо более гибкий и используется повсеместно для подобных целей.
В статье так не написано. Русский язык тоже гибкий. И crontab тоже. Вашу задачу (много задач в crontab) теперь придется поддерживать, если вдруг надо поменять расписание запуска какого либо скрипта, нужно деплоить код, в который программист вася обязательно нагадит с обратной совместимостью: ), а если проект растет по настоящему, то 1им сервером не обойтись и нужно все это запустить на 3-10 серверах… а еще рестарт крона будет накапливать задержки, вообщем ждите беды и готовьтесь к худшему.
А если не хотите беды и хотите пить кофе, то сделайте демона, и натравите на него супервизор.
Простой планировщик задач на PHP