I have a struct like:
type Notifications struct {
Id int
Start *time.Time
}
notifications := db.GetNotifications()
So now I need to send out these notifications whenever the time matches the current time.
1 2018-11-07 09:05:00
2 2018-11-07 09:05:00
3 2018-11-07 09:15:00
..
The simplest way for me to do this is with a ticker:
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
for {
<-ticker.C
alerts := []Notification
for _, n := range notifications {
if n.Start == // same year, month, day, hour and minute {
alerts = append(alerts, n)
}
}
sendNotifications(alerts)
// TODO mutate the notifications to avoid duplicatation sending
}
Is there a more efficient way to do be doing this?
What is the best way to match on the time, do I have to compare time.Now()'s attributes like year, month, day, hour and minute individually in my if statement? i.e. A notification is triggered if the year,month,day,hour and minute have been reached (seconds and beyond are ignored)
First things first, to compare time values, use the Time.Equal, Time.Before, and time.After methods. Comparing the individual components is not reliable at all:
newYork, _ := time.LoadLocation("America/New_York")
t1 := time.Date(2018, 11, 8, 4, 0, 0, 0, time.UTC)
t2 := t1.In(newYork)
fmt.Printf("%v == %v?\n", t1, t2) // 2018-11-08 04:00:00 +0000 UTC == 2018-11-07 23:00:00 -0500 EST?
fmt.Println(t1.Day() == t2.Day()) // false
fmt.Println(t2.Equal(t1)) // true
https://play.golang.org/p/06RcvuI_1Ha
For the scheduling problem I would use a time.Timer.
Here is a sketch:
package main
import "time"
func main() {
t := time.NewTimer(0)
go func() {
for range t.C {
nextTwo := db.GetNextNotifications(2)
// Sanity check
if time.Until(nextTwo[0].Start) > 1*time.Second {
// The timer went off early. Perhaps the notification has been
// deleted?
t.Reset(time.Until(nextTwo[0].Start))
continue
}
go send(nextTwo[0])
t.Reset(time.Until(nextTwo[1].Start))
}
}()
resetTimer(t) // call as required whenever a notification is added or removed
}
func resetTimer(t *time.Timer) {
next := db.GetNextNotification()
t.Reset(time.Until(next.Start))
}