# Планировщик асинхронных заданий. Прошлое, настоящее и будущее. ## Прошлое или как появился планировщик. Вкратце на вопрос, зачем я написал свой планировщик асинхронных заданий можно ответить так: потому, что я устал ждать, когда это сделает кто-то другой. С 2007 года я занимался биллингом. Изначально он был написан на перле с базой пострегс, позднее его частично перевели на джангу. Большинство задач в биллинге можно было решать прямо в базе. Например, что-то посчитать, протарифицировать, включить, выключить. Но решались они внешними скриптами на перле и питоне, которые по сути выполняли всего лишь SQL-запросы в базе. Поэтому когда на очередном собеседовании летом 2018 меня спросили, что мне не хватает в постгресе, я не задумываясь на первом месте назвал асинхронные триггеры. (На втором месте - внешние ключи на партицированные таблицы. На третьем - мультимастер.) Асинхронные триггеры - это как триггеры, но только выполняются асинхронно. Например, клиент в биллинге совершает платёж на свой лицевой счёт через платёжный шлюз. Платёжный шлюз запрашивает информацию у биллинга на существование такого лицевого счёта и на возможность пополнения баланса. В случае успешного ответа платёж совершается. Далее биллинг считает баланс для лицевого счёта и в зависимости от результата может совершать дальнейшие действия, например, включить телефон/интернет. Все эти действия по-сути являются просто SQL-запросами в базе и могут быть зашиты в хранимки и триггеры. Но обычные триггеры синхронны по отношению к запросу. Поэтому в таком случае платёжному шлюзу пришлось бы ждать, пока биллинг завершит все нужные действия, хотя они вовсе не обязательны для платёжного шлюза. А вот в случае асинхронных триггеров данные действия могут выполняться асинхронно, не тормозя платёжный шлюз, сколько бы их не было и как бы долго они не выполнялись. Сначала я поискал, что есть готового для решения этого вопроса и нашёл 1) [PGQ](https://github.com/pgq/pgq) - асинхронные очереди прямо в базе 2) [pg_cron](https://github.com/citusdata/pg_cron) - cron прямо в базе 3) [pg_background](https://github.com/vibhorkum/pg_background) - выполнение запроса в фоне асинхронно и конечно же коммерческий планировщик [pgpro_scheduler](https://habr.com/ru/company/postgrespro/blog/335798/) Позже, когда я уже написал свой планировщик, я случайно нашёл один открытый планировщик [generic-scheduler](https://github.com/okbob/generic-scheduler). Сначала я попытался заюзать асинхронные очереди [PGQ](https://github.com/pgq/pgq). Для работы они требуют [управляющего-тикера](https://github.com/pgq/pgqd) - внешнюю программу, которая нарезает задачи для выполнения исполнителям - тоже внешним программам, которые постоянно опрашивают базу на предмет новых задач для них. Подобная архитектура меня не устроила и первое, что я сделал - это перенёс тикера в базу в качестве фонового рабочего процесса. Так появилась первоначальная версия моего планировщика [pgqbw](https://github.com/RekGRpth/pgqbw). Но всё равно исполнители оставались внешними программами и более того, какое-то их количество должно быть всегда запущено, даже если задач для них совсем нет. Такой подход меня не устроил, мне бы хотелось динамически запускать исполнителей при наличии задач и останавливать их при отсутствии задач. Подобным образом работает [pg_cron](https://github.com/citusdata/pg_cron), но на тот момент у него было много других ограничений, которые меня тоже не устраивали. Например, он проверял появление новых заданий не чаще чем раз в минуту (мой планировщик может проверять не чаще чем раз в миллисекунду). Также [pg_cron](https://github.com/citusdata/pg_cron) не мог выполнять одновременно несколько задач (мой планировщик не имеет такого ограничения). Ещё [pg_cron](https://github.com/citusdata/pg_cron) мог быть запущен только в одной базе для всего кластера (мой планировщик может запускаться в каждой базе да не по разу если надо). Кроме того, [pg_cron](https://github.com/citusdata/pg_cron) - это был просто cron, т.е. какие-то периодические задачи, там нельзя было что-то выполнить один раз в определённую дату в определённое время. Также мне не подошёл [pg_background](https://github.com/vibhorkum/pg_background), потому, что это просто асинхронное выполнение запроса в фоне, причём почти бесконтрольно. Поэтому, т.к. я не смог использовать найденные открытые решения так как мне надо, я решил написать свой планировщик асинхронных заданий и назвал его [pg_task](https://github.com/RekGRpth/pg_task). ## Настоящее или что умеет планировщик. ## Будущее или как устроен планировщик.