2026-09-26projects/cronator.mdcronator.md

Cronator: когда cron начинает болеть

≈ 3 минуты

У каждого, кто немного занимается автоматизацией, в какой-то момент появляется папка со скриптами. Бэкапы баз, отчёты по расписанию, синхронизация данных, уведомления, чистка логов. Всё это работает через crontab, и работает нормально, пока не перестаёт.

Cron хороший. Cron молчит. Скрипт упал в три ночи с ошибкой импорта, и ты узнаёшь об этом утром, когда кто-то спросит, почему отчёт не пришёл. Или не узнаёшь вообще. Добавляешь логирование в каждый скрипт, и теперь логи в пяти разных местах. Virtualenv не активировался, скрипт молча запустился с системным Python и упал на импорте. Два скрипта запустились одновременно, получил гонку данных.

Я смотрел в сторону Airflow и Prefect. Это другой масштаб: оркестраторы с DAG-ами, операторами, концепцией pipeline. У меня десяток скриптов, которым нужно надёжно запускаться по расписанию и кричать, если что-то пошло не так.

Так появился Cronator. В апреле я про него писал, с тех пор в нём больше сотни коммитов, поэтому статью переписал.

Идея та же: веб-интерфейс для Python-скриптов по расписанию. Каждый скрипт живёт в своём virtualenv через uv, с выбранной версией Python и своими зависимостями. История запусков с stdout, stderr, кодом выхода и длительностью, логи приходят в браузер по SSE, пока скрипт ещё работает. Ретраи с задержкой и окном, защита от одновременных запусков: вместо второго экземпляра в истории появляется запись SKIPPED с объяснением. Письмо или вебхук при падении, по желанию и при успехе. Всё в одном docker compose up.

Что добавилось с апреля. Библиотека cronator_lib: тот же get_logger() в терминале печатает цветной вывод, а внутри Cronator отдаёт JSON построчно, а интерфейс раскрашивает строки по уровням, прогресс и таймеры видны прямо в логе. save_artifact() кладёт файл рядом с запуском, так бэкап или CSV-отчёт видны прямо в истории. Каждое выполнение хранит версию скрипта, которой запускалось, поэтому «а что там было в прошлый вторник» открывается одной кнопкой, рядом «запустить ещё раз». На дашборде отдельный блок для скриптов, которые упали сегодня или не запускались неделю. Появились пользователи с ролями, локаут после десяти неудачных логинов, CSRF-защита и CSP, /metrics для Prometheus и /api/diagnostics для разбора инцидентов.

Под капотом FastAPI и SQLAlchemy на asyncpg, Jinja2-шаблоны с Tailwind и daisyUI, CodeMirror в редакторе, APScheduler для расписания, PostgreSQL с Alembic и ежедневным pg_dump. Для разработки хватает SQLite.

git clone https://github.com/aa-blinov/cronator
cd cronator
cp .env.example .env   # ADMIN_PASSWORD, SECRET_KEY, POSTGRES_PASSWORD
docker compose up -d

Открываешь localhost:8080, добавляешь скрипт или берёшь один из 19 шаблонов, выставляешь cron-выражение, готово. Если упадёт и включён SMTP, придёт письмо.

Цель была одна: перестать бояться, что скрипт упал и никто не знает. Пять месяцев спустя цель та же, просто теперь я ещё и вижу, что именно он напечатал перед смертью.

Cronator закрывает конкретную нишу, больше, чем cron, меньше, чем Airflow, для тех, у кого просто скрипты.

Мы движемся в сторону мира, где автономные агенты сами ставят себе задачи и сами их исполняют. Cronator это переходный этап: рутинное уже можно отдать автоматике, а контроль над тем, что действительно важно, остаётся в руках через нормальный интерфейс. Между crontab в терминале и чёрным ящиком агента есть место, где ты видишь, что происходит, и можешь вмешаться.