From 446ab3b1b88175ce8f10781a6a75b43b1a068e30 Mon Sep 17 00:00:00 2001 From: naiba Date: Thu, 2 Sep 2021 23:45:21 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20dashboard:=20=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E7=9B=91=E6=8E=A7=E8=AF=B7=E6=B1=82=E6=97=B6=E9=97=B4=E9=97=B4?= =?UTF-8?q?=E9=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- cmd/dashboard/controller/member_api.go | 7 ++- cmd/dashboard/main.go | 9 +++- cmd/dashboard/rpc/rpc.go | 54 +++++++++---------- model/api.go | 2 +- model/monitor.go | 15 +++++- resource/static/main.js | 4 +- resource/template/common/footer.html | 2 +- resource/template/component/monitor.html | 4 ++ resource/template/dashboard/monitor.html | 2 + service/dao/dao.go | 2 +- service/dao/servicesentinel.go | 66 ++++++++++++++++++++---- 12 files changed, 119 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 5998860..8bc3d0a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@
LOGO designed by 熊大 .

-    +   

:trollface: 哪吒监控 一站式轻监控轻运维系统。支持系统状态、HTTP(SSL 证书变更、即将到期、到期)、TCP、Ping 监控报警,命令批量执行和计划任务。

diff --git a/cmd/dashboard/controller/member_api.go b/cmd/dashboard/controller/member_api.go index 23added..25d65e8 100644 --- a/cmd/dashboard/controller/member_api.go +++ b/cmd/dashboard/controller/member_api.go @@ -204,6 +204,7 @@ type monitorForm struct { Cover uint8 Notify string SkipServersRaw string + Duration uint64 } func (ma *memberAPI) addOrEditMonitor(c *gin.Context) { @@ -218,6 +219,7 @@ func (ma *memberAPI) addOrEditMonitor(c *gin.Context) { m.SkipServersRaw = mf.SkipServersRaw m.Cover = mf.Cover m.Notify = mf.Notify == "on" + m.Duration = mf.Duration } if err == nil { if m.ID == 0 { @@ -226,14 +228,15 @@ func (ma *memberAPI) addOrEditMonitor(c *gin.Context) { err = dao.DB.Save(&m).Error } } + if err == nil { + err = dao.ServiceSentinelShared.OnMonitorUpdate(m) + } if err != nil { c.JSON(http.StatusOK, model.Response{ Code: http.StatusBadRequest, Message: fmt.Sprintf("请求错误:%s", err), }) return - } else { - dao.ServiceSentinelShared.OnMonitorUpdate() } c.JSON(http.StatusOK, model.Response{ Code: http.StatusOK, diff --git a/cmd/dashboard/main.go b/cmd/dashboard/main.go index a3ba025..9343c73 100644 --- a/cmd/dashboard/main.go +++ b/cmd/dashboard/main.go @@ -17,7 +17,11 @@ import ( "github.com/naiba/nezha/service/dao" ) +var serviceSentinelDispatchBus chan model.Monitor + func init() { + serviceSentinelDispatchBus = make(chan model.Monitor) + shanghai, err := time.LoadLocation("Asia/Shanghai") if err != nil { panic(err) @@ -55,7 +59,7 @@ func initSystem() { dao.DB.AutoMigrate(model.Server{}, model.User{}, model.Notification{}, model.AlertRule{}, model.Monitor{}, model.MonitorHistory{}, model.Cron{}, model.Transfer{}) - dao.NewServiceSentinel() + dao.NewServiceSentinel(serviceSentinelDispatchBus) loadServers() //加载服务器列表 loadCrons() //加载计划任务 @@ -65,6 +69,7 @@ func initSystem() { if err != nil { panic(err) } + // 流量记录打点 _, err = dao.Cron.AddFunc("0 * * * *", recordTransferHourlyUsage) if err != nil { @@ -173,7 +178,7 @@ func loadCrons() { func main() { cleanMonitorHistory() go rpc.ServeRPC(dao.Conf.GRPCPort) - go rpc.DispatchTask(time.Second * 30) + go rpc.DispatchTask(serviceSentinelDispatchBus) go dao.AlertSentinelStart() srv := controller.ServeWeb(dao.Conf.HTTPPort) graceful.Graceful(func() error { diff --git a/cmd/dashboard/rpc/rpc.go b/cmd/dashboard/rpc/rpc.go index 2a3bfd0..02604d1 100644 --- a/cmd/dashboard/rpc/rpc.go +++ b/cmd/dashboard/rpc/rpc.go @@ -3,7 +3,6 @@ package rpc import ( "fmt" "net" - "time" "google.golang.org/grpc" @@ -25,41 +24,36 @@ func ServeRPC(port uint) { server.Serve(listen) } -func DispatchTask(duration time.Duration) { - var index uint64 = 0 - for { - var hasAliveAgent bool - tasks := dao.ServiceSentinelShared.Monitors() +func DispatchTask(serviceSentinelDispatchBus <-chan model.Monitor) { + workedServerIndex := 0 + for task := range serviceSentinelDispatchBus { + round := 0 + prevIndex := workedServerIndex dao.SortedServerLock.RLock() - startedAt := time.Now() - for i := 0; i < len(tasks); i++ { - if index >= uint64(len(dao.SortedServerList)) { - index = 0 - if !hasAliveAgent { - break - } - hasAliveAgent = false - } - - // 1. 如果服务器不在线,跳过这个服务器 - if dao.SortedServerList[index].TaskStream == nil { - i-- - index++ + // 如果已经轮了一整圈没有合适机器去请求,跳出循环 + for round == 0 && prevIndex != workedServerIndex { + // 如果到了圈尾,再回到圈头,圈数加一,游标重置 + if workedServerIndex == len(dao.SortedServerList) { + workedServerIndex = 0 + round++ continue } - // 2. 如果此任务不可使用此服务器请求,跳过这个服务器(有些 IPv6 only 开了 NAT64 的机器请求 IPv4 总会出问题) - if (tasks[i].Cover == model.MonitorCoverAll && tasks[i].SkipServers[dao.SortedServerList[index].ID]) || - (tasks[i].Cover == model.MonitorCoverIgnoreAll && !tasks[i].SkipServers[dao.SortedServerList[index].ID]) { - i-- - index++ + // 如果服务器不在线,跳过这个服务器 + if dao.SortedServerList[workedServerIndex].TaskStream == nil { + workedServerIndex++ continue } - - hasAliveAgent = true - dao.SortedServerList[index].TaskStream.Send(tasks[i].PB()) - index++ + // 如果此任务不可使用此服务器请求,跳过这个服务器(有些 IPv6 only 开了 NAT64 的机器请求 IPv4 总会出问题) + if (task.Cover == model.MonitorCoverAll && task.SkipServers[dao.SortedServerList[workedServerIndex].ID]) || + (task.Cover == model.MonitorCoverIgnoreAll && !task.SkipServers[dao.SortedServerList[workedServerIndex].ID]) { + workedServerIndex++ + continue + } + // 找到合适机器执行任务,跳出循环 + dao.SortedServerList[workedServerIndex].TaskStream.Send(task.PB()) + workedServerIndex++ + break } dao.SortedServerLock.RUnlock() - time.Sleep(time.Until(startedAt.Add(duration))) } } diff --git a/model/api.go b/model/api.go index 039429c..50085e9 100644 --- a/model/api.go +++ b/model/api.go @@ -1,7 +1,7 @@ package model type ServiceItemResponse struct { - Monitor Monitor + Monitor *Monitor TotalUp uint64 TotalDown uint64 CurrentUp uint64 diff --git a/model/monitor.go b/model/monitor.go index 852af27..f3e7cbd 100644 --- a/model/monitor.go +++ b/model/monitor.go @@ -2,8 +2,10 @@ package model import ( "encoding/json" + "fmt" pb "github.com/naiba/nezha/proto" + "github.com/robfig/cron/v3" "gorm.io/gorm" ) @@ -36,9 +38,12 @@ type Monitor struct { Type uint8 Target string SkipServersRaw string + Duration uint64 Notify bool Cover uint8 - SkipServers map[uint64]bool `gorm:"-" json:"-"` + + SkipServers map[uint64]bool `gorm:"-" json:"-"` + CronJobID cron.EntryID `gorm:"-" json:"-"` } func (m *Monitor) PB() *pb.Task { @@ -49,6 +54,14 @@ func (m *Monitor) PB() *pb.Task { } } +func (m *Monitor) CronSpec() string { + if m.Duration == 0 { + // 默认间隔 30 秒 + m.Duration = 30 + } + return fmt.Sprintf("@every %ds", m.Duration) +} + func (m *Monitor) AfterFind(tx *gorm.DB) error { var skipServers []uint64 if err := json.Unmarshal([]byte(m.SkipServersRaw), &skipServers); err != nil { diff --git a/resource/static/main.js b/resource/static/main.js index 370283a..1d231ea 100644 --- a/resource/static/main.js +++ b/resource/static/main.js @@ -55,7 +55,8 @@ function showFormModal(modelSelector, formID, URL, getData) { item.name === "RequestMethod" || item.name === "DisplayIndex" || item.name === "Type" || - item.name === "Cover" + item.name === "Cover" || + item.name === "Duration" ) { obj[item.name] = parseInt(item.value); } else { @@ -218,6 +219,7 @@ function addOrEditMonitor(monitor) { modal.find("input[name=ID]").val(monitor ? monitor.ID : null); modal.find("input[name=Name]").val(monitor ? monitor.Name : null); modal.find("input[name=Target]").val(monitor ? monitor.Target : null); + modal.find("input[name=Duration]").val(monitor && monitor.Duration ? monitor.Duration : 30); modal.find("select[name=Type]").val(monitor ? monitor.Type : 1); modal.find("select[name=Cover]").val(monitor ? monitor.Cover : 0); if (monitor && monitor.Notify) { diff --git a/resource/template/common/footer.html b/resource/template/common/footer.html index 51b5831..6ca4524 100644 --- a/resource/template/common/footer.html +++ b/resource/template/common/footer.html @@ -9,7 +9,7 @@ - + diff --git a/resource/template/component/monitor.html b/resource/template/component/monitor.html index 3aaa3cf..332cf69 100644 --- a/resource/template/component/monitor.html +++ b/resource/template/component/monitor.html @@ -24,6 +24,10 @@ +
+ + +