Size: a a a

Clojure — русскоговорящее сообщество

2020 February 25

AR

Andrew Rudenko in Clojure — русскоговорящее сообщество
Andrew Rudenko
я бы на твоем месте:

1. для каждого юзера хранил конфиг расписания
2. для каждого юзера хранил время следующего срабатывания по расписанию
3. в воркере делал select * where trigger_at < now() и выполнял таски
 3.a. сюда же можешь добавить лок по row например, так что воркеры можно и параллельно выполнять без проблем

trigger_at можешь вычислять по какой угодно сложной логике и тебе не придется для этого мапить ее на sql
4. при обновлении конфига ты пересчитываешь trigger_at
источник

TP

Tim Plotnikov in Clojure — русскоговорящее сообщество
Andrew Rudenko
я бы на твоем месте:

1. для каждого юзера хранил конфиг расписания
2. для каждого юзера хранил время следующего срабатывания по расписанию
3. в воркере делал select * where trigger_at < now() и выполнял таски
 3.a. сюда же можешь добавить лок по row например, так что воркеры можно и параллельно выполнять без проблем

trigger_at можешь вычислять по какой угодно сложной логике и тебе не придется для этого мапить ее на sql
И потом trigger_at обновлять на каждом выполнении?
источник

AR

Andrew Rudenko in Clojure — русскоговорящее сообщество
Tim Plotnikov
И потом trigger_at обновлять на каждом выполнении?
да
источник

TP

Tim Plotnikov in Clojure — русскоговорящее сообщество
Если честно, попахивает возможными ошибками (пока не могу сказать какими, просто gut feeling).
Да и чувствовать я себя буду гораздо спокойнее, если моя логика не будет зависеть от того, сколько раз выполнилась функция)
источник

AR

Andrew Rudenko in Clojure — русскоговорящее сообщество
Tim Plotnikov
Если честно, попахивает возможными ошибками (пока не могу сказать какими, просто gut feeling).
Да и чувствовать я себя буду гораздо спокойнее, если моя логика не будет зависеть от того, сколько раз выполнилась функция)
твоя логика тут никак не зависит от того сколько раз ты выполнил функцию
источник

AR

Andrew Rudenko in Clojure — русскоговорящее сообщество
делаешь select и апдейт в транзации и опционально делаешь row based lock для активации мультворкерности
источник

AR

Andrew Rudenko in Clojure — русскоговорящее сообщество
Tim Plotnikov
Если честно, попахивает возможными ошибками (пока не могу сказать какими, просто gut feeling).
Да и чувствовать я себя буду гораздо спокойнее, если моя логика не будет зависеть от того, сколько раз выполнилась функция)
это попахивает правильной архитектурой 😉

1. простое
2. корректное
3. гибкое (логика скедулинга никак не завязана на БД)
4. имеет неограниченные возможности для скейла
источник

AR

Andrew Rudenko in Clojure — русскоговорящее сообщество
тебе так же придется ответить на некоторые вопросы типа:

- что если новый trigger_at меньше now()?

и то что этот вопрос становится очевидным это следствие 1., на самом деле тебе нужно отвечать на этот вопрос в любом случае, в том числе с кварцем, просто там это спрятано во флажки джоба / триггеринга
источник

TP

Tim Plotnikov in Clojure — русскоговорящее сообщество
Проблема заключается в том, что выполнение функции будет зависит от предыдущего результата.
А что если у меня в 23:59:59 (или какой-нибудь другой супер редкий кейс) triggered_at посчитался неправильно?
Это значит что и следующие значения будут неправильными. Это может стать охренительным снежным комом, ведь помните историю с американской ракетной установкой, когда там часы сдвиг давали, что они потом попасть ракетой никуда не могли?)
источник

AR

Andrew Rudenko in Clojure — русскоговорящее сообщество
нет, это просто делает для тебя очевидным, что скедулинг алгоритм должен быть идемпонтентым и иметь интерфейс: get-trigger-at(config, now)
источник

AR

Andrew Rudenko in Clojure — русскоговорящее сообщество
как именно этого добиться решаешь ты. например точкой отсчета брать начало юникс эпохи
источник

AR

Andrew Rudenko in Clojure — русскоговорящее сообщество
Tim Plotnikov
Если честно, попахивает возможными ошибками (пока не могу сказать какими, просто gut feeling).
Да и чувствовать я себя буду гораздо спокойнее, если моя логика не будет зависеть от того, сколько раз выполнилась функция)
возможными ошибками попахивает попытка замапить скедулинг алгоритм на реляционную алгебру
источник

AR

Andrew Rudenko in Clojure — русскоговорящее сообщество
или использование кварца, который на смом деле делает РОВНО то же самое. пихает в БД triggers и высчитывает следующее время его активации (я тут не на 100 процентов уверен, но на 90). только добавляет тебе парочку лишних и текущих (от слова течь) слоев абстракции
источник

TP

Tim Plotnikov in Clojure — русскоговорящее сообщество
Реляционная алгебра здесь не при чем)
Мне нужна функция вида
getUsersToNotify(now: Date, allUsers: [User]) -> [User]
источник

TP

Tim Plotnikov in Clojure — русскоговорящее сообщество
Шедулинг сам по себе и база (способ хранения данных) это второстепенно
источник

ST

Sergey Trofimov in Clojure — русскоговорящее сообщество
Tim Plotnikov
Реляционная алгебра здесь не при чем)
Мне нужна функция вида
getUsersToNotify(now: Date, allUsers: [User]) -> [User]
так, как предлагает тебе Андрей, ты и получаешь
источник

TP

Tim Plotnikov in Clojure — русскоговорящее сообщество
Sergey Trofimov
так, как предлагает тебе Андрей, ты и получаешь
Его решение делает нежелательный сайд эффект
источник

AR

Andrew Rudenko in Clojure — русскоговорящее сообщество
Tim Plotnikov
Реляционная алгебра здесь не при чем)
Мне нужна функция вида
getUsersToNotify(now: Date, allUsers: [User]) -> [User]
ты в своем изначальном предложении пытался мапить скедулинг логику на реляционную алгебру
источник

AR

Andrew Rudenko in Clojure — русскоговорящее сообщество
Tim Plotnikov, [25. Feb 2020 at 16:07:38]:
...А ещё такой момент, как обыграть кейс, когда чувак например ставит step = 2 и у него получается, что он должен получать нотификации в 10 в 12 в 14 etc?

типа HOUR(now) % step == 0 должно сработать?
источник

AR

Andrew Rudenko in Clojure — русскоговорящее сообщество
вот это вот все
источник