Я запускаю службу, в которой пользователи загружают продолжительность, и функция должна многократно выполняться каждый раз, когда таймер истекает.
Например, пользователь говорит «Выполнять каждые 5 минут», а затем эту функцию нужно запускать каждые 5 минут. Это делается через API.
Для небольшого количества таймеров это тривиально:
func doEvery(d time.Duration, f func(time.Time)) {
for x := range time.Tick(d) {
f(x) // Run the function every d duration
}
}
Я могу запускать каждый таймер в горутине, и это прекрасно работает. Я могу запускать и останавливать все с помощью некоторых базовых функций WaitGroups
и синхронизации.
Но что, если у меня есть тысячи или миллионы таймеров? Я могу создать горутину для каждого из них, но это кажется очень неэффективным. Это не Эрланг.
Должен ли я иметь несколько рабочих очередей, отсортированных по «задержке», и просто выделять больше рабочих для более частых функций? Если таймер не готов, он снова ставится в очередь.
Это также не идеально, потому что рабочие заняты ожиданием (выходят, проверяют время, помещают в очередь), а не блокируются, пока не закончится следующий таймер.
Может быть, я мог бы иметь какую-то карту, проиндексированную оставшейся продолжительностью? Я не уверен, какой лучший подход здесь.
Недавно я создал такое решение, в котором пользователь получает уведомление в зависимости от настроек интервала. Я делаю модель рабочего пула, используя rabbitMQ и два скрипта go. Где скрипт one go использует нижеприведенный модуль cron для создания заданий в очереди сообщений
https://github.com/robfig/cron
Другой скрипт go — это рабочий скрипт, использующий очередь сообщений и выполняющий действия. Для масштабирования я запускаю несколько экземпляров рабочего скрипта. Автомасштабирование рабочего скрипта можно сделать по количеству сообщений в rabbitMQ