From 33c32f1e026482d60de635656a53de723114fcb7 Mon Sep 17 00:00:00 2001 From: Kevin Chabowski Date: Sat, 14 Sep 2013 12:42:30 +0200 Subject: checkjobs (was checkmails) now recovers from panics --- checkjobs.go | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++ checkmails.go | 65 ---------------------------------------------- main.go | 4 +-- model/mysql/jobs.go | 5 ++-- 4 files changed, 80 insertions(+), 69 deletions(-) create mode 100644 checkjobs.go delete mode 100644 checkmails.go diff --git a/checkjobs.go b/checkjobs.go new file mode 100644 index 0000000..2b4af74 --- /dev/null +++ b/checkjobs.go @@ -0,0 +1,75 @@ +package main + +import ( + "bytes" + "fmt" + "kch42.de/gostuff/mailremind/model" + "log" + "time" +) + +var checkInterval int64 + +func initCheckjobs() { + var err error + if checkInterval, err = conf.GetInt("schedules", "checkInterval"); err != nil { + log.Fatalf("Could not read config schedules.checkInterval: %s", err) + } +} + +func checkjobs() { + timech := make(chan time.Time) + go func(ch chan time.Time) { + ticker := time.NewTicker(time.Duration(checkInterval) * time.Second) + + ch <- time.Now() + for t := range ticker.C { + ch <- t + } + }(timech) + + for t := range timech { + checkjobsOnce(t) + } +} + +func checkjobsOnce(t time.Time) { + defer func() { + if r := recover(); r != nil { + log.Printf("!! recovered from panic in checkjobsOnce: %s", r) + } + }() + + jobs := dbcon.JobsBefore(t) + + for _, job := range jobs { + if sendjob(job, t) { + next := job.Chronos().NextAfter(t) + if next.IsZero() { + if err := job.Delete(); err != nil { + log.Printf("Failed deleting job %s after job was done: %s", job.ID(), err) + } + } else { + if err := job.SetNext(next); err != nil { + log.Printf("Filed setting next for job %s: %s", job.ID(), err) + } + } + } + } +} + +func sendjob(job model.Job, t time.Time) bool { + user := job.User() + buf := new(bytes.Buffer) + + fmt.Fprintf(buf, "From: %s\n", MailFrom) + fmt.Fprintf(buf, "To: %s\n", user.Email()) + fmt.Fprintf(buf, "Subject: %s\n", job.Subject()) + fmt.Fprintf(buf, "Date: %s\n", t.In(user.Location()).Format(time.RFC1123Z)) + + fmt.Fprintln(buf, "") + + buf.Write(job.Content()) + + return Mail(user.Email(), MailFrom, buf.Bytes()) +} diff --git a/checkmails.go b/checkmails.go deleted file mode 100644 index 576c2c2..0000000 --- a/checkmails.go +++ /dev/null @@ -1,65 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "kch42.de/gostuff/mailremind/model" - "log" - "time" -) - -var checkInterval int64 - -func initCheckmails() { - var err error - if checkInterval, err = conf.GetInt("schedules", "checkInterval"); err != nil { - log.Fatalf("Could not read config schedules.checkInterval: %s", err) - } -} - -func checkmails() { - timech := make(chan time.Time) - go func(ch chan time.Time) { - ticker := time.NewTicker(time.Duration(checkInterval) * time.Second) - - ch <- time.Now() - for t := range ticker.C { - ch <- t - } - }(timech) - - for t := range timech { - jobs := dbcon.JobsBefore(t) - - for _, job := range jobs { - if sendjob(job, t) { - next := job.Chronos().NextAfter(t) - if next.IsZero() { - if err := job.Delete(); err != nil { - log.Printf("Failed deleting job %s after job was done: %s", job.ID(), err) - } - } else { - if err := job.SetNext(next); err != nil { - log.Printf("Filed setting next for job %s: %s", job.ID(), err) - } - } - } - } - } -} - -func sendjob(job model.Job, t time.Time) bool { - user := job.User() - buf := new(bytes.Buffer) - - fmt.Fprintf(buf, "From: %s\n", MailFrom) - fmt.Fprintf(buf, "To: %s\n", user.Email()) - fmt.Fprintf(buf, "Subject: %s\n", job.Subject()) - fmt.Fprintf(buf, "Date: %s\n", t.In(user.Location()).Format(time.RFC1123Z)) - - fmt.Fprintln(buf, "") - - buf.Write(job.Content()) - - return Mail(user.Email(), MailFrom, buf.Bytes()) -} diff --git a/main.go b/main.go index 02bcdbe..ddb17ce 100644 --- a/main.go +++ b/main.go @@ -79,8 +79,8 @@ func main() { log.Fatalf("Could not get net.laddr config: %s", err) } - initCheckmails() - go checkmails() + initCheckjobs() + go checkjobs() router := mux.NewRouter() router.PathPrefix("/static").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(staticpath)))) diff --git a/model/mysql/jobs.go b/model/mysql/jobs.go index 2695d50..1b9598b 100644 --- a/model/mysql/jobs.go +++ b/model/mysql/jobs.go @@ -134,7 +134,8 @@ func (j *Job) Next() time.Time { return j.next } func (j *Job) User() model.User { u, err := j.con.UserByID(j.user) if err != nil { - // TODO: Should we really panic here? If yes, we need to recover panics! + // We panic here, since the user must exist, if the job is there. + // Since http handlers and the job handler do recover from panics, this should be okay. panic(fmt.Errorf("Could not get user (%d) of Job %d: %s", j.user, j.id, err)) } @@ -185,7 +186,7 @@ func (j *Job) Delete() error { func (con *MySQLDBCon) JobsBefore(t time.Time) (jobs []model.Job) { rows, err := con.stmt[qJobsBefore].Query(t.Unix()) if err != nil { - log.Fatalf("Could not get jobs before %s: %s", t, err) // TODO: Really fatal? + log.Fatalf("Could not get jobs before %s: %s", t, err) } for rows.Next() { -- cgit v1.2.3-54-g00ecf