Sto cercando di progettare il modo migliore per inviare promemoria agli utenti per gli eventi per i quali sono registrati:
- i promemoria devono essere inviati 72, 48 e 24 ore prima dell'evento
- i promemoria non possono essere inviati due volte (quindi l'utente A registrato a un evento B dovrebbe ricevere al massimo 3 notifiche)
- se gli utenti si registrano dopo uno dei tre intervalli, non riceveranno ovviamente il precedente
- i tempi degli eventi non possono essere modificati dopo che la prima registrazione è in
Questa è un'app Rails con Sidekiq e Redis (in questo momento si invia una notifica al momento della registrazione che non è in programma).
Vedo almeno due modi per risolvere questo problema:
A. Pianifica i lavori al momento della registrazione
- se il tempo di registrazione è precedente a 72 ore dall'evento, quindi pianifica una notifica (data dell'evento - 72 ore) e accodala
- se il tempo di registrazione è precedente a 48 ore dall'evento, quindi pianifica una notifica (data dell'evento - 48 ore) e accodala
- se il tempo di registrazione è precedente a 24 ore dall'evento, quindi pianifica una notifica (data dell'evento - 24 ore) e accodala
Questo dovrebbe coprire i seguenti scenari:
- se l'utente rimuove il suo appuntamento in uno qualsiasi dei telegrammi non riceverà le altre notifiche (i lavori in coda semplicemente falliranno)
- un utente non può ricevere due volte la stessa notifica perché ci sono al massimo 3 lavori programmati
- se l'evento è completamente cancellato dal DB e così sono le sue registrazioni quelle notifiche in coda falliranno
Gli svantaggi:
- probabilmente molti lavori morti in coda se molti utenti annullano la registrazione
- potrebbe accadere che a un utente venga inviata una notifica due volte (se si registra, quindi si annulla la registrazione e quindi si registra nuovamente) ma ciò potrebbe essere risolto usando qualcosa come link che consente solo un tipo di lavoro nella corrispondenza della coda in base agli argomenti
B. Polling con un'attività
Fondamentalmente ogni X minuti di un'attività in background (può essere fatto con cron di Unix o le estensioni cron di sidekiq) controlla la tabella "eventi", controlla se sono 72, 48 o 24 ore dall'evento e mette in coda un lavoro immediato per ogni registrazione.
Questo ha alcuni inconvenienti:
- un utente potrebbe perdere una notifica se l'algoritmo di controllo del tempo non è sufficientemente preciso (se si registrano all'interno della finestra di polling potrebbero essere saltati)
- richiede un meccanismo per segnalare che è stata inviata una notifica per un particolare utente. Questo può anche essere risolto facendo affidamento sulla libreria che vieta i lavori con gli stessi argomenti nella coda
Conclusione
Sono propenso per l'approccio "pianificazione anticipata". Non c'è alcuna configurazione cron esterna, non ho bisogno di sottolineare il DB ogni X minuti con query che potrebbero diventare pesanti se ci sono centinaia di eventi con centinaia di utenti registrati e posso monitorare ciò che succede dal dashboard web Sidekiq.
Il polling sembra essere il più facile a causa del fuoco e dimenticare la natura, ma non può essere complicato ottimizzare la linea. Un enorme vantaggio del polling è che non richiede un Redis configurato con persistenza. Se la macchina (o Redis) viene riavviata, la successiva iterazione cron si limiterà a riprendere da dove era stata interrotta.
La soluzione di pianificazione richiede una Redis con persistenza configurata perché se la macchina viene riavviata perderà tutti i lavori pianificati, ma questo potrebbe essere un problema in generale, quindi è solo un requisito generale.
Qualche idea? Mi manca qualcosa?