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