cloud-castle / crone
Планировщик задач и парсер cron-выражений для PHP 8.1+: синтаксис 5/6/7 полей (секунды и годы), @-макросы, интервалы @every и @reboot, префикс TZ=, спецсимволы L/W/#/? и Jenkins-H, вычисление next/prev/between с таймзонами и явной политикой DST, перевод расписаний на 6 языков, планировщик задач с за
Requires
- php: >=8.1
- cloud-castle/clock: ^1.0
- cloud-castle/inflector: ^1.7
Requires (Dev)
- crunzphp/crunz: ^3.4
- deptrac/deptrac: ^3.0 || ^4.0
- dragonmantank/cron-expression: ^3.4
- ergebnis/composer-normalize: ^2.45
- friendsofphp/php-cs-fixer: ^3.75
- icanhazstring/composer-unused: ^0.9
- infection/infection: ^0.29 || ^0.33
- lorisleiva/cron-translator: ^0.4
- peppeocchi/php-cron-scheduler: ^4.0
- php-parallel-lint/php-parallel-lint: ^1.4
- phpmd/phpmd: ^2.15
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^1.12 || ^2.1
- phpstan/phpstan-deprecation-rules: ^1.2 || ^2.0
- phpstan/phpstan-phpunit: ^1.4 || ^2.0
- phpstan/phpstan-strict-rules: ^1.6 || ^2.0
- phpunit/phpunit: ^10.5 || ^11.5
- poliander/cron: ^3.1
- psalm/plugin-phpunit: ^0.19 || ^0.20
- rector/rector: ^1.2 || ^2.0
- roave/security-advisories: dev-latest
- squizlabs/php_codesniffer: ^3.12 || ^4.0
- vimeo/psalm: ^6.0
- webmozart/assert: ^1.11
Suggests
- ext-pcntl: Жёсткое прерывание задач по таймауту через SignalTimeout
- cloud-castle/command: Обёртка задач планировщика в консольные команды CLI
- cloud-castle/lock: Распределённые мьютексы для onOneServer() в кластере
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-15 06:26:27 UTC
README
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano
CloudCastle Crone
Планировщик задач и парсер cron-выражений для PHP 8.1+. Синтаксис из 5, 6 (с секундами) и 7 (с годом) полей,
@-макросы, интервалы@every 90s,@reboot, префикс таймзоныTZ=, спецсимволыL,W,#,?, Jenkins-хешHи случайноеR. Вычислениеnext/prev/between/isDue«прыжковым» поиском с учётом таймзон и переводов часов, перевод расписания на шесть языков, реестр задач с защитой от наложения, повторами, таймаутами, приоритетами, тегами и healthcheck, а также импорт и экспорт crontab. Runtime-зависимости — только экосистема cloud-castle:cloud-castle/clock(PSR-20 часы) иcloud-castle/inflector(правила счёта языков).
Установка
composer require cloud-castle/crone
Требуется PHP 8.1+. Рекомендуемое ограничение версии — ^1.0.
Быстрый старт
Разбор выражения и вычисление дат
<?php
use CloudCastle\Crone\CronExpression;
$cron = CronExpression::fromString('0 9 * * 1-5'); // будни в 09:00
$cron->getNextRunDate(); // ближайший будний день в 09:00
$cron->getPreviousRunDate(); // предыдущий запуск
$cron->isDue('2026-07-31 09:00:00'); // true — пятница 09:00
$cron->getMultipleRunDates(3); // три ближайшие даты запуска
$cron->describe('ru'); // «в 09:00 по понедельникам, …»
CronExpression::isValid('*/15 * * * *'); // true
CronExpression::isValid('0 0 30 2 *'); // false — 30 февраля недостижимо
Расписание словами — без ручного составления строк
use CloudCastle\Crone\Builder\CronBuilder;
CronBuilder::create()->dailyAt('03:30')->weekdays()->build(); // '30 3 * * 1-5'
CronBuilder::create()->lastWeekdayOfMonth('18:00')->build(); // '0 18 LW * *'
CronBuilder::create()->everyFifteenMinutes()->between(9, 18)->build(); // '*/15 9-18 * * *'
Планирование задач
use CloudCastle\Crone\Scheduler\Lock\FileMutex;
use CloudCastle\Crone\Scheduler\Schedule;
use CloudCastle\Crone\Scheduler\Scheduler;
$schedule = new Schedule();
$schedule->call(fn () => backup(), 'nightly-backup')
->dailyAt('03:30') // расписание текучим API
->weekdays() // только по будням
->withoutOverlapping() // защита от наложения
->retries(2, 30) // две повторные попытки с паузой 30 с
->timeout(600) // лимит выполнения
->priority(10) // раньше остальных задач
->tag('backup') // выборочный запуск по тегу
->environments('production') // только в проде
->when(fn () => disk_has_space())
->onFailure(fn ($result) => alert($result));
$scheduler = new Scheduler(new FileMutex(sys_get_temp_dir()));
foreach ($scheduler->runDue($schedule, 'production') as $result) {
// статус, вывод, исключение, длительность, попытки, память
log_result($result->key, $result->status->name, $result->duration);
}
Возможности
- Полный синтаксис — 5/6/7 полей (секунды и год),
@-макросы (включая@quarterly,@weekdays,@secondly), интервалы@every 1h30m,@reboot, префикс таймзоныTZ=/CRON_TZ=, диапазоны, списки, шаги, алиасыJAN–DECиSUN–SAT, спецсимволыL,L-3,LW,15W,5#3,5L,?, Jenkins-хешH,H/15,H(0-29)и случайноеR. - Вычисление дат —
isDue,next,prev,multiple,between,count, ленивый итератор и «сколько секунд до запуска». Поиск «прыжковый»: несовпавшее поле сразу переводится к ближайшему допустимому значению. - Классическая семантика секунд — пятиполевое расписание срабатывает в любую секунду подходящей минуты (как системный cron), а поле секунд становится значимым только когда оно написано явно.
- Таймзоны и переход на летнее время — вычисления ведутся в наивном времени
и локализуются в конце, поэтому исчезнувший час распознаётся явно:
политика
DstPolicy::Skip(как Vixie cron) илиDstPolicy::Shift(как systemd-таймеры). - Перевод на естественный язык — двадцать языков, от русского и английского до арабского, китайского и хинди, с правилами счёта каждого языка, включая спецсимволы и интервалы.
- Нормализация и сравнение — каноническая форма выражения и
equals()для проверки смысловой эквивалентности (*/15≡0,15,30,45). - Безопасность чужого ввода — типизированный отказ на некорректном выражении, предел шагов поиска недостижимой даты, ограниченный кэш разбора и защита экспорта crontab от инъекции перевода строки.
- Планировщик задач — текучее API частот (
everyFiveMinutes(),dailyAt(),weeklyOn(),lastDayOfMonth()…), условияwhen/skip, окружения, теги, приоритеты, повторы с паузой, мягкий и жёсткий таймаут, защита от наложения и режим «только на одном сервере», хуки жизненного цикла, healthcheck-монитор и метрики выполнения. - Crontab в обе стороны — разбор существующего crontab (с переменными,
комментариями и
CRON_TZ) и экспорт расписания в готовый crontab с экранированием ключей задач. - Детерминизм в тестах — источник времени внедряется через PSR-20 часы, паузы и метрики — через собственные контракты.
Примеры по возможностям
Спецсимволы календаря
CronExpression::fromString('0 9 L * *'); // последний день месяца
CronExpression::fromString('0 9 L-3 * *'); // за три дня до конца месяца
CronExpression::fromString('0 9 LW * *'); // последний рабочий день месяца
CronExpression::fromString('0 9 15W * *'); // ближайший рабочий день к 15-му
CronExpression::fromString('0 9 * * 5#3'); // третья пятница месяца
CronExpression::fromString('0 9 * * 5L'); // последняя пятница месяца
Размазывание нагрузки: Jenkins-хеш
// Сотня задач с одинаковым расписанием стартует в разные минуты,
// но у каждой задачи момент запуска стабилен между перезапусками.
$cron = CronExpression::fromString('H * * * *', seed: 'report-generator');
$cron->normalize(); // например, '0 47 * * * *'
Интервалы и запуск при старте
$every = CronExpression::fromString('@every 90s');
$every->getNextRunDate('2026-07-31 09:02:13'); // 09:03:00 — сетка от эпохи Unix
$reboot = CronExpression::fromString('@reboot');
$reboot->isReboot(); // true — плановых дат нет, запуск при старте системы
Таймзоны и переход на летнее время
use CloudCastle\Crone\Expression\DstPolicy;
$cron = CronExpression::fromString('TZ=Europe/Berlin 30 2 * * *');
$cron->getNextRunDate('2026-03-28 12:00:00'); // 2026-03-30 02:30 — час пропущен
$cron->withDstPolicy(DstPolicy::Shift)
->getNextRunDate('2026-03-28 12:00:00'); // 2026-03-29 03:30 — сдвиг вперёд
Перевод расписания на естественный язык
$cron = CronExpression::fromString('0 9 * * 5L');
$cron->describe('ru'); // «в 09:00 в пятницу последней недели месяца»
$cron->describe('en'); // «at 09:00 on Friday of the last week of the month»
$cron->describe('de'); // «um 09:00 am Freitag der letzten Woche des Monats»
$cron->describe('ja'); // «09:00 に 毎月最終週の金曜日»
Все поддерживаемые языки
| Код | Язык | Пример описания `0 9 * * 1-5` | |---|---|---| | `ru` | Русский | в 09:00 по понедельникам, вторникам, средам, четвергам и пятницам | | `en` | English | at 09:00 on Mondays, Tuesdays, Wednesdays, Thursdays and Fridays | | `de` | Deutsch | um 09:00 montags, dienstags, mittwochs, donnerstags und freitags | | `fr` | Français | à 09:00 les lundis, les mardis, les mercredis, les jeudis et les vendredis | | `es` | Español | a las 09:00 los lunes, los martes, los miércoles, los jueves y los viernes | | `it` | Italiano | alle 09:00 il lunedì, il martedì, il mercoledì, il giovedì e il venerdì | | `uk` | Українська | о 09:00 по понеділках, вівторках, середах, четвергах і п’ятницях | | `pl` | Polski | o 09:00 w poniedziałki, wtorki, środy, czwartki i piątki | | `sk` | Slovenčina | o 09:00 v pondelky, utorky, stredy, štvrtky a piatky | | `nl` | Nederlands | om 09:00 op maandagen, dinsdagen, woensdagen, donderdagen en vrijdagen | | `pt` | Português | às 09:00 às segundas-feiras, terças-feiras, quartas-feiras, quintas-feiras e sextas-feiras | | `da` | Dansk | kl. 09:00 på mandage, tirsdage, onsdage, torsdage og fredage | | `ro` | Română | la 09:00 în fiecare luni, marți, miercuri, joi și vineri | | `lv` | Latviešu | plkst. 09:00 pirmdienās, otrdienās, trešdienās, ceturtdienās un piektdienās | | `tr` | Türkçe | saat 09:00 pazartesi günleri, salı günleri, çarşamba günleri, perşembe günleri ve cuma günleri | | `hi` | हिन्दी | 09:00 बजे सोमवार को, मंगलवार को, बुधवार को, गुरुवार को और शुक्रवार को | | `ar` | العربية | في 09:00 في أيام الاثنين، أيام الثلاثاء، أيام الأربعاء، أيام الخميس وأيام الجمعة | | `zh` | 中文 | 在 09:00 每周一、每周二、每周三、每周四和每周五 | | `ja` | 日本語 | 09:00 に 毎週月曜日、毎週火曜日、毎週水曜日、毎週木曜日と毎週金曜日 | | `vi` | Tiếng Việt | lúc 09:00 vào thứ hai hằng tuần, thứ ba hằng tuần, thứ tư hằng tuần, thứ năm hằng tuần và thứ sáu hằng tuần |Импорт и экспорт crontab
use CloudCastle\Crone\Scheduler\Crontab\CrontabExporter;
use CloudCastle\Crone\Scheduler\Crontab\CrontabParser;
$crontab = <<<'CRON'
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.daily; }
47 6 * * 7 root test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.weekly; }
CRON;
$entries = (new CrontabParser())->parse($crontab); // или file_get_contents('/etc/crontab')
foreach ($entries as $entry) {
echo $entry->command, ' → ', $entry->expression->describe('ru'), PHP_EOL;
}
echo (new CrontabExporter('php bin/schedule run {task}'))->export($schedule);
Healthcheck и метрики
use CloudCastle\Crone\Scheduler\Heartbeat\CallableHeartbeat;
$schedule->call(fn () => sync(), 'sync')
->everyFiveMinutes()
->heartbeat(new CallableHeartbeat(
static fn (string $key) => ping("https://hc.example.com/{$key}/start"),
static fn ($result) => ping("https://hc.example.com/{$result->key}/" . $result->status->name),
));
Справочник API
| Класс | Назначение |
|---|---|
CloudCastle\Crone\CronExpression | разбор, проверка, вычисление дат, перевод, нормализация |
CloudCastle\Crone\Builder\CronBuilder | текучее построение выражений |
CloudCastle\Crone\Expression\DstPolicy | политика перехода на летнее время |
CloudCastle\Crone\Expression\ExpressionNormalizer | каноническая форма выражения |
CloudCastle\Crone\Translator\ExpressionTranslator | перевод расписания на двадцать языков |
CloudCastle\Crone\Scheduler\Schedule | реестр задач и фабрики расписаний |
CloudCastle\Crone\Scheduler\Task | настройка задачи: частота, условия, хуки, повторы |
CloudCastle\Crone\Scheduler\Scheduler | запуск наступивших задач и сбор результатов |
CloudCastle\Crone\Scheduler\TaskResult | исход, вывод, исключение и метрики выполнения |
CloudCastle\Crone\Scheduler\Lock\FileMutex | файловая защита от наложения |
CloudCastle\Crone\Scheduler\Timeout\SignalTimeout | жёсткий таймаут на сигналах POSIX |
CloudCastle\Crone\Scheduler\Crontab\CrontabParser | разбор crontab-файлов |
CloudCastle\Crone\Scheduler\Crontab\CrontabExporter | экспорт расписания в crontab |
Полный справочник — в wiki и в документации API.
Сравнение с аналогами
Все таблицы ниже сгенерированы автоматически из честных сравнительных прогонов (benchmarks/compare.php и benchmarks/analyse.php) на ОДИНАКОВОЙ операции и по единым правилам анализа для всех участников, PHP 8.3.32, без Xdebug.
1. Функциональность
| Возможность | CloudCastle | dragonmantank | poliander | peppeocchi | crunz |
|---|---|---|---|---|---|
| Разбор 5 полей | ✅ | ✅ | ✅ | ✅ | ✅ |
| Секунды (6 полей) | ✅ | ❌ | ❌ | ❌ | ❌ |
| Год (7 полей) | ✅ | ❌ | ❌ | ❌ | ❌ |
| Спецсимволы L / W / # | ✅ | ✅ | ❌ | ✅ | ✅ |
| Смещение от конца месяца (L-n) | ✅ | ❌ | ❌ | ❌ | ❌ |
| Jenkins-хеш H | ✅ | ❌ | ❌ | ❌ | ❌ |
| Случайное значение R | ✅ | ✅ | ❌ | ❌ | ❌ |
| Интервалы @every | ✅ | ❌ | ❌ | ❌ | ❌ |
| Запуск при старте @reboot | ✅ | ❌ | ❌ | ❌ | ❌ |
| Таймзона в выражении (TZ=) | ✅ | ❌ | ❌ | ❌ | ❌ |
| Политика перехода на летнее время | ✅ | ❌ | ❌ | ❌ | ❌ |
| Даты в промежутке и подсчёт запусков | ✅ | ❌ | ❌ | ❌ | ❌ |
| Ленивый итератор дат | ✅ | ❌ | ❌ | ❌ | ❌ |
| Нормализация и сравнение выражений | ✅ | ❌ | ❌ | ❌ | ❌ |
| Перевод расписания на язык | ✅ | ❌ | ❌ | ❌ | ❌ |
| Построитель выражений | ✅ | ❌ | ❌ | ✅ | ✅ |
| Планировщик задач | ✅ | ❌ | ❌ | ✅ | ✅ |
| Защита от наложения | ✅ | ❌ | ❌ | ❌ | ✅ |
| Повторы при ошибке | ✅ | ❌ | ❌ | ❌ | ❌ |
| Таймаут выполнения задачи | ✅ | ❌ | ❌ | ❌ | ❌ |
| Теги и приоритеты задач | ✅ | ❌ | ❌ | ❌ | ❌ |
| Метрики выполнения | ✅ | ❌ | ❌ | ❌ | ❌ |
| Импорт и экспорт crontab | ✅ | ❌ | ❌ | ❌ | ❌ |
| Без сторонних runtime-зависимостей | ✅ | ✅ | ✅ | ✅ | ❌ |
| Всего | 🏆 24 | 4 | 2 | 5 | 5 |
2. Корректность сложных расписаний
| Свойство | CloudCastle | dragonmantank | poliander | peppeocchi | crunz |
|---|---|---|---|---|---|
| последний день месяца (L) | ✅ | ✅ | ❌ | ❌ | ❌ |
| ближайший рабочий день (15W) | ✅ | ✅ | ❌ | ❌ | ❌ |
| третья пятница (5#3) | ✅ | ✅ | ❌ | ❌ | ❌ |
| секунды (6 полей) | ✅ | ❌ | ❌ | ❌ | ❌ |
| год (7 полей) | ✅ | ❌ | ❌ | ❌ | ❌ |
| интервал @every 90s | ✅ | ❌ | ❌ | ❌ | ❌ |
| Всего | 🏆 6 | 3 | 0 | 0 | 0 |
3. Производительность
Разбор 6 расписаний и проверка 4 моментов, 2 000 раз (минимум из 4 прогонов).
| Решение | Время (мс) | Итог |
|---|---|---|
| наивно¹ | 84,5 | базовый уровень (не библиотека) |
| 🏆 CloudCastle | 220,1 | быстрейшее среди библиотек |
| poliander | 478,1 | аналог |
| dragonmantank | 2 968,4 | аналог |
| peppeocchi | 3 522,6 | аналог |
| crunz | 4 518,5 | аналог |
4. Потребление памяти
Собственный след библиотеки (изолированный процесс, дельта к baseline без библиотеки).
| Решение | Память (KB) | Итог |
|---|---|---|
| наивно¹ | 1 | базовый уровень (не библиотека) |
| 🏆 poliander | 44 | легчайшее среди библиотек |
| dragonmantank | 184 | аналог |
| peppeocchi | 265 | аналог |
| CloudCastle | 285 | аналог |
| crunz | 358 | аналог |
5. Утечки памяти
Рост памяти на второй волне из 5 000 новых уникальных выражений после такой же первой (0 — библиотека не течёт).
| Решение | Рост памяти (KB) | Итог |
|---|---|---|
| 🏆 CloudCastle | 0 | не течёт (рост 0) |
| dragonmantank | 0 | аналог |
| poliander | 0 | аналог |
| peppeocchi | 0 | аналог |
| crunz | 0 | аналог |
| наивно¹ | 0 | базовый уровень (не библиотека) |
6. Безопасность
Проверяется по исходникам установленного пакета и реальными вызовами: отказ на мусорном выражении и конечное время поиска недостижимой даты.
| Критерий | CloudCastle | dragonmantank | poliander | peppeocchi | crunz | наивно¹ |
|---|---|---|---|---|---|---|
| Не исполняет команды оболочки | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
| Не десериализует данные (unserialize) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Без eval и extract | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Не подавляет ошибки оператором @ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Отклоняет некорректное выражение исключением | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ |
| Бросает собственные типизированные исключения | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Ограничивает поиск недостижимой даты | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| Поток чужих выражений не наращивает память | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Политика безопасности в пакете | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Всего | 🏆 9 | 7 | 6 | 5 | 5 | 4 |
7. Статический анализ по единым правилам
Синтаксический линтер, PSR-12 и PHPMD с конфигурацией этого пакета прогоняются по исходникам каждого участника; число замечаний нормировано на тысячу строк кода.
| Решение | Замечаний на 1000 строк | Итог |
|---|---|---|
| 🏆 CloudCastle | 0,0 | чище всех по единым правилам |
| crunz | 11,8 | аналог |
| poliander | 22,3 | аналог |
| peppeocchi | 22,4 | аналог |
| dragonmantank | 33,6 | аналог |
8. Качество кода
| Критерий | CloudCastle | dragonmantank | poliander | peppeocchi | crunz |
|---|---|---|---|---|---|
| Строгая типизация во всех файлах (declare(strict_types=1)) | ✅ | ❌ | ❌ | ❌ | ✅ |
| Типы возвращаемых значений у всех публичных методов | ✅ | ❌ | ❌ | ❌ | ❌ |
| Требует современный PHP 8.1+ | ✅ | ❌ | ✅ | ❌ | ✅ |
| Без сторонних runtime-зависимостей (кроме PSR/ext/cloud-castle) | ✅ | ✅ | ✅ | ❌ | ❌ |
| Всего | 🏆 4 | 1 | 2 | 0 | 2 |
9. Инструменты качества в пакете
| Критерий | CloudCastle | dragonmantank | poliander | peppeocchi | crunz |
|---|---|---|---|---|---|
| Собственные тесты в пакете | ✅ | ❌ | ✅ | ✅ | ❌ |
| Конфигурация статического анализа | ✅ | ❌ | ❌ | ❌ | ❌ |
| Конфигурация стандарта кодирования | ✅ | ❌ | ❌ | ❌ | ❌ |
| Мутационное тестирование | ✅ | ❌ | ❌ | ❌ | ❌ |
| Всего | 🏆 4 | 0 | 1 | 1 | 0 |
10. Перевод расписаний
Сколько языков поддерживает перевод расписания в человекочитаемый вид.
| Решение | Языков | Итог |
|---|---|---|
| 🏆 CloudCastle | 20 | богатейший набор языков |
| lorisleiva | 17 | аналог |
| dragonmantank | 0 | аналог |
| poliander | 0 | аналог |
| peppeocchi | 0 | аналог |
| crunz | 0 | аналог |
¹ Базовый уровень (примитивная проверка без полноты решения) показан для контекста и не претендует на победу среди библиотек-аналогов.
Замеры выполняются на одинаковой операции: разобрать расписание и проверить
набор моментов — именно это делает планировщик на каждом тике. Планировщики
peppeocchi и crunz внутри используют dragonmantank/cron-expression, поэтому
их числа отражают путь исполнения через публичный API обёртки. Память измеряется
как собственный след библиотеки: в изолированном процессе из результата
вычитается baseline — тот же процесс с автозагрузчиком и данными, но без единого
класса библиотеки. Утечки проверяются двумя волнами новых уникальных выражений
одинаковой формы. Признаки качества кода читаются из исходников установленных
пакетов, а не из заявлений авторов.
Вывод: CloudCastle Crone — самый быстрый среди сравниваемых библиотек и функционально богатейший: один пакет закрывает разбор, вычисление, перевод, построение, планирование и работу с crontab, тогда как аналоги покрывают лишь часть пути. Плата за это — собственный след памяти выше, чем у минималистичных парсеров: пакет держит в памяти и планировщик, и словари шести языков. Этот компромисс осознанный и единственный: по функциональности, скорости, отсутствию утечек и безопасности пакет не уступает никому из сравниваемых.
Плюсы, минусы и когда применять
Плюсы:
- Функциональный суперсет экосистемы: парсер, вычислитель, переводчик,
построитель, планировщик и работа с crontab в одном пакете — обычно это
dragonmantank/cron-expression+lorisleiva/cron-translator+crunz. - Синтаксис шире, чем у аналогов: секунды и год,
L/W/#, Jenkins-хешH, случайноеR, интервалы@every,@reboot, префиксTZ=. - Явная политика перехода на летнее время — расписание не «съедает» и не задваивает запуски молча.
- Две runtime-зависимости, обе из экосистемы cloud-castle (
clockиinflector); планировщик не тянет Symfony-компоненты. - Детерминизм в тестах: часы, паузы и метрики внедряются через контракты.
- Перевод расписания на двадцать языков — больше, чем у специализированного переводчика, с правилами счёта каждого языка.
- Безопасность проверяется, а не декларируется: девять признаков из девяти, включая ограниченный поиск даты, устойчивость памяти к потоку чужих выражений и защиту экспорта crontab от инъекции.
- 100% покрытие строк, 100% Infection MSI, весь строгий статанализ зелёный; те же правила на исходниках аналогов дают от 12 до 34 замечаний на 1000 строк.
Минусы:
- Пакет моложе и менее распространён, чем
dragonmantank/cron-expression(сотни миллионов установок, используется ядром Laravel): меньше ответов на Stack Overflow и готовых рецептов в интернете. - Собственный след памяти выше, чем у минималистичных парсеров: пакет держит
в памяти разбор, планировщик, переводчик и словари двадцати языков, тогда как
poliander/cronумеет только проверять пять полей. Это осознанный компромисс: функциональностью, скоростью и отсутствием утечек ради экономии памяти не жертвуем — точные числа в таблицах выше.
Когда применять:
- Планировщик без фреймворка — cron-подобный запуск задач в standalone-
приложении, демоне или контейнере, где Laravel избыточен, а
crunzтянет половину Symfony. - Пользовательские расписания в SaaS — строгая валидация, перевод на язык пользователя и защита от недостижимых выражений (anti-DoS).
- Массовые однотипные задачи — Jenkins-хеш
Hразводит сотни задач по минутам без ручного подбора расписаний. - Миграция с системного crontab — импорт существующего файла, анализ расписаний и обратный экспорт после переноса задач в код.
- Финтех и критичные операции — защита от наложения, повторы с паузой, таймауты и healthcheck делают запуск задач с деньгами предсказуемым.
- Не нужен, если задача — просто «проверить, подходит ли строка
* * * * *» в проекте, гдеdragonmantank/cron-expressionуже стоит транзитивно: там выигрыш от перехода минимален.
Разработка
composer install
composer check # линтеры + статический анализ + тесты
composer fix # автоисправления (Rector, PHP CS Fixer, PHPCBF)
composer ci # полный CI-пайплайн локально
Полный список команд с описаниями: composer run-script --list.
Документация
- Репозиторий: https://gitverse.ru/cloud-castle/crone
- Wiki: https://gitverse.ru/cloud-castle/crone/wiki
- История изменений: CHANGELOG.md
- Обновление между версиями: UPGRADING.md
- Как внести вклад: CONTRIBUTING.md
- Кодекс поведения: CODE_OF_CONDUCT.md
- Безопасность расписаний: страница wiki
- Политика безопасности: SECURITY.md
- Поддержка: SUPPORT.md
Лицензия
MIT © CloudCastle (alex-4-17@yandex.ru)
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano