예제 #1
0
func (s *EmailServer) queueToDb() {

	var em email.Email
	wait, _ := time.ParseDuration("5m")

	for {
		d, err := s.queue.PopWait(wait)
		panik.On(err)
		if len(d) > 0 {
			// read from queue
			//err = ds.LoadStruct(&em, d)
			err = ds.Load(&em, d)
			if err != nil {
				log.Error("Error reading email from queue", "email", em, "error", err)
				panik.On(err)
			}

			// save to db
			m := Message{
				Data:      string(d),
				Priority:  em.Priority,
				CreatedAt: time.Now().Unix(),
				SendAfter: em.SendAfter,
			}
			err = s.dbo.Create(&m).Error
			if err != nil { // on error, put back in queue
				s.queue.Push(d)
				panik.On(err)
			}
		}
	}
}
예제 #2
0
func NewEmailServer() *EmailServer {

	es := EmailServer{
		dbo: orm.ReadConfig("email.server.database"),
		auth: smtp.PlainAuth(
			conf.String("", "email.server.smtp.auth", "identity"),
			conf.String("", "email.server.smtp.auth", "username"),
			conf.String("", "email.server.smtp.auth", "password"),
			conf.String("", "email.server.smtp.auth", "host"),
		),
	}

	// testing
	es.dbo.LogMode(true)

	es.address = conf.String("", "email.server.smtp", "host")
	if conf.Exists("email.server.smtp", "port") {
		es.address = fmt.Sprintf("%s:%d", es.address, conf.Int(0, "email.server.smtp", "port"))
	}

	if conf.Exists("email.queue.default") {
		es.queue = que.NewQueue("email.queue.default")
	}

	// create relational tables if missing
	if !es.dbo.HasTable(Message{}) {
		panik.On(es.dbo.AutoMigrate(&Message{}).Error)
		fmt.Println("[message] table created.")
	}

	return &es
}
예제 #3
0
func (s *EmailServer) Run() {
	go s.queueToDb()

	batch := conf.Int(3, "email", "server", "batch")
	maxFails := conf.Int(3, "email", "server", "max-fails")
	maxTime := conf.String("1h", "email", "server", "max-time")
	dur, err := time.ParseDuration(maxTime)
	panik.On(err)
	maxTimeSec := int(dur.Seconds())
	now := time.Now().Unix()

	var upd map[string]interface{}
	var msgs []Message

	sql := `
	  sent = 0
	  and num_fails < ?
	  and ((send_after is null and ? - created_at between 0 and ?) or
	  (send_after is not null and ? - send_after between 0 and ?))`

	for {
		s.dbo.Where(sql, maxFails, now, maxTimeSec, now, maxTimeSec).
			Order("priority desc, created_at asc").
			Limit(batch).
			Find(&msgs)

		if len(msgs) == 0 {
			time.Sleep(5 * time.Second)
		} else {
			for i := 0; i < len(msgs); i++ {
				err := s.dispatchMessage(&msgs[i])
				now = time.Now().Unix()
				if err == nil {
					upd = map[string]interface{}{
						"sent":       1,
						"sent_at":    &now,
						"updated_at": &now,
					}
				} else {
					upd = map[string]interface{}{
						"num_fails":      msgs[i].NumFails + 1,
						"last_failed_at": &now,
						"failure":        err.Error(),
						"updated_at":     &now,
					}
				}
				edb := s.dbo.Model(Message{}).Where("id = ?", msgs[i].Id).Updates(upd).Error
				panik.On2(edb, func() {
					log.Error("Failed to update message table", "email-err", err, "db-err", edb)
				})
			}
		}
	}
}
예제 #4
0
func (e *Email) Enque() {

	if mails == nil { // initialization
		startLoop()
	}

	go func() {
		d, err := ds.ToBytes(e, false)
		panik.On(err)
		mails <- d
	}()
}
예제 #5
0
func startLoop() {
	if mails != nil {
		return
	}

	mails = make(chan []byte, conf.Int(size, "email", "buffer"))
	panik.If(Queue == nil, "Queue is not initialized")

	go func() {
		for {
			select {
			case mb := <-mails:
				err := Queue.Push(mb)
				panik.On(err)
			}
		}
	}()
}
예제 #6
0
func (e *Email) SendLater(after string) {
	d, err := time.ParseDuration(after)
	panik.On(err)
	e.SendAt(time.Now().Add(d))
}