Как я уже писал в
предыдущем сообщении, в разрабатываемой в данный момент версии IntB появилась такая возможность, как асинхронные задания (они же tasks). Впервые необходимость в них возникла тогда, когда я задумал добавить в Intellect Board поддержку протокола ActivityPub для взаимодействия с fediverse. Этот протокол работает по PUSH-модели, когда сервер сам отправляет уведомления подписчикам. При этом спецификация протокола требует, чтобы в случае ошибки попытка отправки уведомления повторялась ещё раз через какое-то время.
Технически асинхронные задания во многом аналогичны заданиям обычного планировщика, но есть ряд отличий. В частности, выполняемый код также должен лежать в библиотеке в каталоге lib в классе, унаследованном от Library, но название дожлно начинаться не с cron_, а с task_. Асинхронное задание считается выполненным, если функция возвращает либо 0, либо 200. Если же возвращается другое задание или выбрасывается исключение (exception), задание считается невыполненным. В этом случае оно будет повторно запущено через некоторое время. Это время определяется как количество минут, равное количеству предыдущих неудачных попыток запуска. То есть после первой неудачи задание будет перезапущено через минуту, после второй — через две и так далее. После 127 неудачных попыток задание считается невыполнимым и удаляется.
В базе данных информация о заданиях хранится не в таблице prefix_crontab, а в prefix_task. Там же находится счётчик попыток выполнения и время следующей попытки. Важное отличие: если для задач планировщика параметры хранятся в обычной строке, так как предполагают возможность редактирования из Центра Администрирования, то для асинхронных заданий — сериализуются через PHP-функцию serialize. Это даёт больше гибкости для передачи параметров.
Добавить новую задачу можно с помощью метода create_task в библиотеке misc. Он принимает следующие параметры: $library — имя библиотеки, где лежит выполняемый код, $proc — имя вызываемого метода (без task_ в начале),$params — параметры в произвольном виде (сериализация делается внутри самого create_task), $nextrun — время следующего выполнения (по умолчанию равно нулю, что означает выполнить как только будет возможность).
Сам запуск осуществляется из файла www/cron.php после выполнения задач обычного планировщика. При этом скрипт учитывает, сколько времени осталось до конца его выполнения и выбирает задачи из расчёта на то, что каждая будет выполнена за 5 секунд. (Если скрипт запускается через системный cron, то время выполнения считается равным 60 секундам).
Сейчас, как уже говорилось, асинхронные задания используются только для протокола WebMention (реализация ActivityPub отложена на неопределённое время). Но сейчас также рассматриваю возможность сделать тег blocklink для вывода ссылки с картинкой и развёрнутым описанием (аналогично тому, как это сделано ВКонтакте и Facebook). Для него также потребуются асинхронные запросы (чтобы закешировать информацию OpenGraph для этого предпросмотра).