mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-02-06 21:50:05 +00:00
✨ [dashboard v0.3.9] 手动即时触发计划任务
This commit is contained in:
110
service/dao/alertsentinel.go
Normal file
110
service/dao/alertsentinel.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/naiba/nezha/model"
|
||||
)
|
||||
|
||||
// 报警规则
|
||||
var alertsLock sync.RWMutex
|
||||
var alerts []model.AlertRule
|
||||
var alertsStore map[uint64]map[uint64][][]interface{}
|
||||
|
||||
type NotificationHistory struct {
|
||||
Duration time.Duration
|
||||
Until time.Time
|
||||
}
|
||||
|
||||
func AlertSentinelStart() {
|
||||
alertsStore = make(map[uint64]map[uint64][][]interface{})
|
||||
notificationsLock.Lock()
|
||||
if err := DB.Find(¬ifications).Error; err != nil {
|
||||
panic(err)
|
||||
}
|
||||
notificationsLock.Unlock()
|
||||
alertsLock.Lock()
|
||||
if err := DB.Find(&alerts).Error; err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for i := 0; i < len(alerts); i++ {
|
||||
alertsStore[alerts[i].ID] = make(map[uint64][][]interface{})
|
||||
}
|
||||
alertsLock.Unlock()
|
||||
|
||||
time.Sleep(time.Second * 10)
|
||||
var lastPrint time.Time
|
||||
var checkCount uint64
|
||||
for {
|
||||
startedAt := time.Now()
|
||||
checkStatus()
|
||||
checkCount++
|
||||
if lastPrint.Before(startedAt.Add(-1 * time.Hour)) {
|
||||
log.Println("报警规则检测每小时", checkCount, "次", startedAt, time.Now())
|
||||
checkCount = 0
|
||||
lastPrint = startedAt
|
||||
}
|
||||
time.Sleep(time.Until(startedAt.Add(time.Second * SnapshotDelay)))
|
||||
}
|
||||
}
|
||||
|
||||
func OnRefreshOrAddAlert(alert model.AlertRule) {
|
||||
alertsLock.Lock()
|
||||
defer alertsLock.Unlock()
|
||||
delete(alertsStore, alert.ID)
|
||||
var isEdit bool
|
||||
for i := 0; i < len(alerts); i++ {
|
||||
if alerts[i].ID == alert.ID {
|
||||
alerts[i] = alert
|
||||
isEdit = true
|
||||
}
|
||||
}
|
||||
if !isEdit {
|
||||
alerts = append(alerts, alert)
|
||||
}
|
||||
alertsStore[alert.ID] = make(map[uint64][][]interface{})
|
||||
}
|
||||
|
||||
func OnDeleteAlert(id uint64) {
|
||||
alertsLock.Lock()
|
||||
defer alertsLock.Unlock()
|
||||
delete(alertsStore, id)
|
||||
for i := 0; i < len(alerts); i++ {
|
||||
if alerts[i].ID == id {
|
||||
alerts = append(alerts[:i], alerts[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func checkStatus() {
|
||||
alertsLock.RLock()
|
||||
defer alertsLock.RUnlock()
|
||||
ServerLock.RLock()
|
||||
defer ServerLock.RUnlock()
|
||||
|
||||
for _, alert := range alerts {
|
||||
// 跳过未启用
|
||||
if alert.Enable == nil || !*alert.Enable {
|
||||
continue
|
||||
}
|
||||
for _, server := range ServerList {
|
||||
// 监测点
|
||||
alertsStore[alert.ID][server.ID] = append(alertsStore[alert.
|
||||
ID][server.ID], alert.Snapshot(server))
|
||||
// 发送通知
|
||||
max, desc := alert.Check(alertsStore[alert.ID][server.ID])
|
||||
if desc != "" {
|
||||
message := fmt.Sprintf("报警规则:%s,服务器:%s(%s),%s,逮到咯,快去看看!", alert.Name, server.Name, server.Host.IP, desc)
|
||||
go SendNotification(message, true)
|
||||
}
|
||||
// 清理旧数据
|
||||
if max > 0 && max < len(alertsStore[alert.ID][server.ID]) {
|
||||
alertsStore[alert.ID][server.ID] = alertsStore[alert.ID][server.ID][len(alertsStore[alert.ID][server.ID])-max:]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
@@ -9,32 +10,27 @@ import (
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/naiba/nezha/model"
|
||||
pb "github.com/naiba/nezha/proto"
|
||||
)
|
||||
|
||||
var Version = "v0.3.9"
|
||||
|
||||
const (
|
||||
SnapshotDelay = 3
|
||||
ReportDelay = 2
|
||||
)
|
||||
|
||||
var Conf *model.Config
|
||||
var (
|
||||
Conf *model.Config
|
||||
Cache *cache.Cache
|
||||
DB *gorm.DB
|
||||
|
||||
var Cache *cache.Cache
|
||||
ServerList map[uint64]*model.Server
|
||||
ServerLock sync.RWMutex
|
||||
|
||||
var DB *gorm.DB
|
||||
|
||||
// 服务器监控、状态相关
|
||||
var ServerList map[uint64]*model.Server
|
||||
var ServerLock sync.RWMutex
|
||||
|
||||
var SortedServerList []*model.Server
|
||||
var SortedServerLock sync.RWMutex
|
||||
|
||||
// 计划任务相关
|
||||
var CronLock sync.RWMutex
|
||||
var Crons map[uint64]*model.Cron
|
||||
var Cron *cron.Cron
|
||||
|
||||
var Version = "v0.3.8"
|
||||
SortedServerList []*model.Server
|
||||
SortedServerLock sync.RWMutex
|
||||
)
|
||||
|
||||
func ReSortServer() {
|
||||
ServerLock.RLock()
|
||||
@@ -54,3 +50,25 @@ func ReSortServer() {
|
||||
return SortedServerList[i].DisplayIndex > SortedServerList[j].DisplayIndex
|
||||
})
|
||||
}
|
||||
|
||||
// =============== Cron Mixin ===============
|
||||
|
||||
var CronLock sync.RWMutex
|
||||
var Crons map[uint64]*model.Cron
|
||||
var Cron *cron.Cron
|
||||
|
||||
func CronTrigger(c *model.Cron) {
|
||||
ServerLock.RLock()
|
||||
defer ServerLock.RUnlock()
|
||||
for j := 0; j < len(c.Servers); j++ {
|
||||
if ServerList[c.Servers[j]].TaskStream != nil {
|
||||
ServerList[c.Servers[j]].TaskStream.Send(&pb.Task{
|
||||
Id: c.ID,
|
||||
Data: c.Command,
|
||||
Type: model.TaskTypeCommand,
|
||||
})
|
||||
} else {
|
||||
SendNotification(fmt.Sprintf("计划任务:%s,服务器:%d 离线,无法执行。", c.Name, c.Servers[j]), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
81
service/dao/notification.go
Normal file
81
service/dao/notification.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/naiba/nezha/model"
|
||||
)
|
||||
|
||||
const firstNotificationDelay = time.Minute * 15
|
||||
|
||||
// 通知方式
|
||||
var notifications []model.Notification
|
||||
var notificationsLock sync.RWMutex
|
||||
|
||||
func OnRefreshOrAddNotification(n model.Notification) {
|
||||
notificationsLock.Lock()
|
||||
defer notificationsLock.Unlock()
|
||||
var isEdit bool
|
||||
for i := 0; i < len(notifications); i++ {
|
||||
if notifications[i].ID == n.ID {
|
||||
notifications[i] = n
|
||||
isEdit = true
|
||||
}
|
||||
}
|
||||
if !isEdit {
|
||||
notifications = append(notifications, n)
|
||||
}
|
||||
}
|
||||
|
||||
func OnDeleteNotification(id uint64) {
|
||||
notificationsLock.Lock()
|
||||
defer notificationsLock.Unlock()
|
||||
for i := 0; i < len(notifications); i++ {
|
||||
if notifications[i].ID == id {
|
||||
notifications = append(notifications[:i], notifications[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SendNotification(desc string, muteable bool) {
|
||||
if muteable {
|
||||
// 通知防骚扰策略
|
||||
nID := hex.EncodeToString(md5.New().Sum([]byte(desc)))
|
||||
var flag bool
|
||||
if cacheN, has := Cache.Get(nID); has {
|
||||
nHistory := cacheN.(NotificationHistory)
|
||||
// 每次提醒都增加一倍等待时间,最后每天最多提醒一次
|
||||
if time.Now().After(nHistory.Until) {
|
||||
flag = true
|
||||
nHistory.Duration *= 2
|
||||
if nHistory.Duration > time.Hour*24 {
|
||||
nHistory.Duration = time.Hour * 24
|
||||
}
|
||||
nHistory.Until = time.Now().Add(nHistory.Duration)
|
||||
// 缓存有效期加 10 分钟
|
||||
Cache.Set(nID, nHistory, nHistory.Duration+time.Minute*10)
|
||||
}
|
||||
} else {
|
||||
// 新提醒直接通知
|
||||
flag = true
|
||||
Cache.Set(nID, NotificationHistory{
|
||||
Duration: firstNotificationDelay,
|
||||
Until: time.Now().Add(firstNotificationDelay),
|
||||
}, firstNotificationDelay+time.Minute*10)
|
||||
}
|
||||
|
||||
if !flag {
|
||||
return
|
||||
}
|
||||
}
|
||||
// 发出通知
|
||||
notificationsLock.RLock()
|
||||
defer notificationsLock.RUnlock()
|
||||
for i := 0; i < len(notifications); i++ {
|
||||
notifications[i].Send(desc)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user