Files
worker/internal/notifier/run_exp.go
Gleb Tv 2c884c5612
Некоторые проверки не удались
CI / test (push) Successful in 2m5s
Docker / Build and publish worker image (push) Failing after 31s
refactor: adopt worker module path
2026-07-13 17:56:12 +03:00

118 строки
2.8 KiB
Go

package notifier
import (
"log"
"time"
"rocketgit.ru/rsmon/worker/app/models"
)
// RunExp provides functionality.
//
// A panic in any single check's notification must not kill the scheduler
// goroutine. The defensive recover() keeps the 2h tick alive even if
// RunExpCheck trips over a bad row or a stale schema reference.
func RunExp() {
defer func() {
if r := recover(); r != nil {
log.Printf("notifier: RunExp recovered from panic: %v", r)
}
}()
_ = models.LogCheck("exp")
checks := make([]models.Check, 0)
err := models.ExpScope(models.DB()).Find(&checks).Error
if err != nil {
log.Println(err)
return
}
for i := range checks {
RunExpCheck(&checks[i])
}
}
// RunExpCheck provides functionality.
//
// A panic in any per-row work (notifier, contact lookup, message write) is
// contained here so one bad row cannot take down the whole RunExp scheduler.
// The panic is logged with the check id and the loop continues.
func RunExpCheck(c *models.Check) {
defer func() {
if r := recover(); r != nil {
log.Printf("notifier: RunExpCheck recovered from panic on check %d: %v", c.ID, r)
}
}()
if c.Monitor == nil {
log.Println("!BUG! check", c.ID, "has no Monitor (or not preloaded). Monitor ID: ", c.MonitorID, " Not running.")
log.Println()
return
}
if !c.Monitor.Enabled {
return
}
if c.Monitor.Group == nil {
log.Println("!BUG! check", c.ID, "has no Monitor (or not preloaded). Monitor ID: ", c.Monitor.ID, ", group id:", c.Monitor.GroupID, " Not running.") //nolint:lll
return
}
if c.Monitor.Group.Notifications == nil {
log.Println("!BUG! check", c.ID, "has no .Monitor.Group.Notifications (or not preloaded). Not running.")
return
}
for i := range c.Monitor.Group.Notifications {
n := &c.Monitor.Group.Notifications[i]
if n.BeforeExpiration == nil {
continue
}
if c.Expires == nil {
// should not happen
continue
}
if c.Kind == "whois" && !n.NotifyWHOIS {
continue
}
if c.Kind == "ssl" && !n.NotifySSL {
continue
}
// notify delay not reached
notifyOn := time.Now().Add(time.Second * time.Duration(*n.BeforeExpiration))
if c.Expires.After(notifyOn) {
continue
}
createExpMessage(c, n)
}
}
func createExpMessage(c *models.Check, n *models.Notification) {
for _, contact := range n.GetContacts() { //nolint:gocritic // range copy is acceptable here
message := models.Message{
CheckID: &c.ID,
NotificationID: n.ID,
ContactID: contact.ID,
Kind: "exp",
}
models.DB().
Where(message).
Where("created_at > ?", time.Now().Add(-time.Hour*24*14)).
Find(&message)
if message.ID > 0 {
continue
}
message.State = models.TaskStateQueued
err := models.DB().Save(&message).Error
if err != nil {
log.Println(err)
return
// panic(err)
}
}
}