Отложенное исполнение
Материал из Eludia.
Содержание |
Eludia содержит механизм, позволяющий откладывать исполнение некоторых вызовов функций (в частности, рассылку e-mail), результаты которых не используются при генерации HTTP-ответов.
Постановка задания в очередь
Чтобы зарегистрировать вызов функции $sub с напором аргументов @params в очереди, нужно воспользоваться подпрограммой
defer ($sub, \@params);
Она также имеет 3-й, необязательный, параметр: набор опций.
defer ($sub, \@params, {label => $label});
Единственная доступная на нынешний момент опция label — это символическое имя задания. Оно может пригодиться для разработки WEB-интерфейса управления очередью, но пока не используется.
Первое применение функции defer — отсрочка рассылки e-mail. Поэтому она интегрирована в функцию send_mail: для того, чтобы при её вызове письма откладывались в очередь, достаточно прописать
defer => 1
в $preconf -> {mail};
Обслуживание очереди
Настройка
Для того, чтобы отложенные вызовы не только запоминались, но и исполнялись, необходимо отдельно позаботиться о часовом механизме. На текущий момент рассматривается единственный вариант: offline-скрипт, запускаемый по cron.
Скрипт должен иметь вид:
#!/usr/bin/perl -w
no warnings;
package MY_APPLICATION;
use Eludia::Offline;
check_deferred ({
cnt => 10,
pidfile => $preconf -> {deferred_pidfile},
});
Как нетрудно видеть, собственно очередь обслуживает функция check_deferred. Опцию pidfile можно не задавать, тогда будет подставлено значение '/var/run/defer_MY_APPLICATION', но если pid-файл задаётся напрямую, то делать это надо обязательно с использованием $preconf.
Опция cnt определяет максимальное количество попыток вызовов, которые инициирует скрипт за 1 раз. Если скрипт будет вторично запущен в то время, как предыдущая копия ещё не отработала, то старый процесс будет прекращён, а последнее задание останется в очереди и его попытаются исполнить вновь.
Если окажется, что какое-то задание никогда не может быть исполнено до аварийного останова скрипта, это не парализует работу очереди, поскольку задания выбираются в случайном порядке.
Строка crontab для вызова скрипта check_deferred.pl раз в 2 минуты с дозаписью stderr в /var/log/deferred.log может иметь вид:
0-55/2 * * * * root perl /var/projects/my_application/lib/offline/check_deferred.pl 2>>/var/log/deferred.log
Чтобы распараллелить обслуживание очереди, следует ввести зависимость имени pid-файла от параметра командной строки скрипта и настроить несколько cron-вызовов.
Соображения эффективности
Итак, очередь параметризуется:
- количеством строк crontab для вызова скрипта;
- частотами запуска для каждой из этих строк;
- количеством заданий, исполняемых за один запуск.
Все эти параметры должны подбираться для каждого сервера отдельно. Следует соблюдать простое правило, вытекающее из теории массового обслуживания: среднее количество запросов, которое можно обслужить в единицу времени, не должно быть меньше, чем среднее количество запросов, поступающих в такую же единицу времени.
Например, если почтовый сервер отправляет письмо не меньше, чем за минуту, и одновременно сервер приложения генерирует 2 почтовых нотификации в минуту, очевидно, количество заданий в очереди будет расти со скоростью 1 вызов в минуту, и задержки в отправке писем быстро сделают нотификации как таковые бессмысленными. Очередь может скомпенсировать отдельные всплески интенсивности заявок, но не ускорить их обслуживание.
Хранение данных
Задания (имена функций и параметры) хранятся в таблице __deferred. Таблица __deferred_hot, имеющая то же пространство id, что __deferred, указывает на те вызовы, которык предстоит исполнить. В таблице __deferred_log фиксируются результаты попыток исполнения запросов.
