@zven_bpe

Что использовать в качестве workerА для отложенных задач?

Пишу бота на aiogram. Админ бота может добавлять события, у которых будет время и дата выполнения. За некоторое время до этого всем пользователям бота должно прийти уведомление об этом. При этом события могут быть отложены на неделю и более. В качестве воркера решил использовать celery, а брокера - redis. Однако, на сайте доки прочитал такую вещь:
Tasks with eta or countdown are immediately fetched by the worker and until the scheduled time passes, they reside in the worker’s memory. When using those options to schedule lots of tasks for a distant future, those tasks may accumulate in the worker and make a significant impact on the RAM usage.
Moreover, tasks are not acknowledged until the worker starts executing them. If using Redis as a broker, task will get redelivered when countdown exceeds visibility_timeout (see Caveats).
Therefore, using eta and countdown is not recommended for scheduling tasks for a distant future. Ideally, use values no longer than several minutes. For longer durations, consider using database-backed periodic tasks, e.g. with https://pypi.org/project/django-celery-beat/ if using Django (see Using custom scheduler classes).

Что значит то, если вкратце, что задачи, отложенные надолго, могут занимать много памяти. Более того, если использовать в качестве брокера redis, то задачи будут доставлятся ​​повторно, когда обратный отсчет превысит Visibility_timeout. Там еще сказано, что идеально не использовать период больше нескольких минут, что вообще не подходит для моей ситуации...
Что посоветуете делать? Менять воркер и/или брокер? Или эти рамки (указанные в доке) не особо строгие? (хотя я понимаю, что это не так) Буду рад любым советам, очень нужна помощь!
  • Вопрос задан
  • 132 просмотра
Пригласить эксперта
Ответы на вопрос 2
Vindicar
@Vindicar
RTFM!
Я бы вообще изобрёл велосипед, если честно.
У тебя есть список или база активных (неслучившихся) событий. Пусть это будет пара ID-метка времени, остальная инфа нам без надобности.
При запуске бота выбираем из списка ближайшее событие, и вычисляем время ожидания (с небольшим запасом) и спим в корутине. В случае, если ожидание прервано раньше - повторяем то же самое, чтобы либо "доспать", либо переключиться на ожидание более близкого события.
Если же ожидание закончилось успешно, обрабатываем событие и снова повторяем поиск ближайшего события.
Если список событий изменился, прерываем текущее ожидание, чтобы корутина ожидания могла адаптироваться к изменениям.

Кода - строк на пятьдесят, не больше, и выносится в отдельный класс на ура. Как мне кажется, если бот не супер-нагружен (в том смысл, что список хранимых событий изменяется не каждую минуту, и событтия тоже срабатывают не так часто), то этого будет вполне достаточно.
А когда он будет так нагружен - проще будет раз в минуту выбирать то, что должно сработать сейчас.
Ответ написан
fenrir1121
@fenrir1121
Начни с документации
Для длительного хранения нужно использовать базу данных, а не redis или selery.
Отдельный воркер вообще не обязателен, если нет вычислительных задач.

Раз в миниту/час/день ходишь в базу и смотришь не наступило ли время выполнения, если наступило выполняешь.

Можно добавить полезных оптимизаций: засыпать до ближайшего события или до инсерта новых записей, читать сразу батчами, держать ближайшие события в памяти и проверять только их, но в целом не обязательно.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы