Как заранее определить все будущие временные точки срабатывания функции, зная период срабатывания,но не храня временные точки в каком-нибудь в списке?
Контекст
Имеется менеджер рассылок.
Каждая из рассылок хранит в себе временную метку, отправителя и список получателей
Временная метка определяет время отправки рассылки и может быть:
- единоразовой (15.01.2025 в 12:30)
- периодической (каждые 3 часа)
- периодической от определённой даты (3 числа каждого месяца в 15:30)
При этом у каждого пользователя имеется лимит на максимальное суммарное количество получателей (по умолчанию - 500).
При создании новой рассылки, если таковая создаётся на на дату, которая попадает в диапазон 24 часа от уже созданной из лимита получателей пользователя вычитается количество получателей этой самой новой рассылки. То есть лимит привязан к дате и пользователю для которого созданы рассылки на эту дату.
В течении 24 часов может быть отправлено не больше лимита получателей пользователя
Проблема
Так как отсутствуют какие либо ограничения на установку времени при создании рассылки пользователи могут создать сразу несколько рассылок, которые активируются в течении 24 часов, превысив лимит на количество пользователей.
Пример:
Допустим у нас имеется 2 периодической рассылки, назначенные в одно и то же время.
Тогда первый раз при ленивом вычислении лимит будет учтён. Если же передвинуть дату второй рассылки на 2 месяца позже, т. к. мы постоянно лениво вычисляем новую дату и она постоянно обновляется, то лимит всё равно вычислится верно.
Ответы (1 шт):
Алгоритм обнаружения конфликтов
Для каждой рассылки создаётся последовательность событий время/количество. Каждому моменту рассылки соответствуют два события: первое в момент рассылки, количество равно числу адресов, второе через 24 часа, количество равно числу адресов со знаком минус. Последовательность не является списком, это генератор, который извлекает последовательные события в хронологическом порядке.
Все последовательности объединяются в одну общую последовательность с помощью обобщения алгоритма слияния упорядоченных массивов. Не обращайте внимание на слово "массив", алгоритм слияния из набора возрастающих последовательностей порождает одну общую возрастающую последовательность.
Заведём счётчик, который будет считать письма отправленные в течение последних 24 часов. Двигаясь последовательно по событиям, к этому счётчику будем прибавлять количества из событий. Отслеживая изменения счётчика можно обнаружить превышение ограничения на отправку писем.
Если рассылки ограничены по времени, то счётчик отслеживается до исчерпания последовательности событий. Если среди рассылок есть бесконечные, счётчик отслеживается на конечном промежутке времени, например, несколько лет.
Модифицируя алгоритм можно давать оценку объёма новой рассылки, которую мы хотим добавить к уже существующим.
Пример
Пусть у нас есть 20 рассылок, каждая из которых отсылает письма раз в сутки. Потребуется память для двадцати генераторов, то есть памяти надо очень мало. Если отслеживать конфликты на десять лет вперёд, то общее количество событий составит около 20·2·365·10 = 146000. Сто сорок шесть тысяч событий обработаются меньше чем за секунду на любом скриптовом языке.