I have to send out thousands of reminders, any way to avoid a ticker every minute?

落爺英雄遲暮 提交于 2020-02-02 14:43:27

问题


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)


回答1:


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.

  1. Figure out which notification is up next
  2. Set or reset the timer accordingly
    1. After the timer fires, goto 1
    2. If a notification is added, goto 1
    3. If a notification is deleted, goto 1

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))
}


来源:https://stackoverflow.com/questions/53198618/i-have-to-send-out-thousands-of-reminders-any-way-to-avoid-a-ticker-every-minut

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!