mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-24 14:55:02 +03:00
feat(notifications): add a failed-check threshold for node.down alerts (#6768)
One lost heartbeat on a lossy link flipped a node offline and sent node.down, and the next probe sent node.up, so a flaky node flooded Telegram, email and Discord with alert pairs. A new nodeDownThreshold setting (default 1, today's behaviour) works like outboundDownThreshold: node.down fires once the failed-check streak reaches it, once per outage, and node.up only after a node.down was sent. The announcement is persisted in nodes.down_notified, so a restart inside the threshold window neither drops the outage's node.down nor re-announces nodes already reported offline; nodes offline at upgrade are seeded as announced.
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/config"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
||||
)
|
||||
|
||||
func TestNodeDownNotifiedSeederMarksOfflineNodesAnnounced(t *testing.T) {
|
||||
t.Setenv("XUI_DB_FOLDER", t.TempDir())
|
||||
if err := InitDB(config.GetDBPath()); err != nil {
|
||||
t.Fatalf("init db: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = CloseDB() })
|
||||
if err := db.Where("seeder_name = ?", "NodeDownNotified").Delete(&model.HistoryOfSeeders{}).Error; err != nil {
|
||||
t.Fatalf("clear seeder history: %v", err)
|
||||
}
|
||||
offline := model.Node{Name: "offline", Address: "10.0.0.1", Port: 1, Status: "offline"}
|
||||
online := model.Node{Name: "online", Address: "10.0.0.2", Port: 1, Status: "online"}
|
||||
for _, n := range []*model.Node{&offline, &online} {
|
||||
if err := db.Create(n).Error; err != nil {
|
||||
t.Fatalf("create node %s: %v", n.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := runSeeders(false); err != nil {
|
||||
t.Fatalf("runSeeders: %v", err)
|
||||
}
|
||||
|
||||
for _, tc := range []struct {
|
||||
node *model.Node
|
||||
want bool
|
||||
}{{&offline, true}, {&online, false}} {
|
||||
var got model.Node
|
||||
if err := db.First(&got, tc.node.Id).Error; err != nil {
|
||||
t.Fatalf("reload node %s: %v", tc.node.Name, err)
|
||||
}
|
||||
if got.DownNotified != tc.want {
|
||||
t.Errorf("node %s DownNotified = %v, want %v", tc.node.Name, got.DownNotified, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user