feat: 离线License批量删除;同步循环加固(启动即跑/pending自动握手/防重入/panic恢复,移至main启动);同步时间显示到秒
This commit is contained in:
1 parent
30b87dec62
commit
252ae14aef
5 files changed
+79
-11
No files matched your search
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"backend/internal/dto"
|
||||
@@ -194,24 +195,49 @@ func formatApplied(m map[string]int) string {
|
||||
|
||||
// ============ 定时循环 ============
|
||||
|
||||
// StartSyncLoop 启动宽松节奏的定时双向同步(默认 10 分钟一轮,失败顺延下轮重试) // Logan.Li
|
||||
// StartSyncLoop 启动宽松节奏的定时双向同步(默认 10 分钟一轮)。
|
||||
// 行为:启动即先跑一轮;active 节点直接交换;pending 节点先自动握手(两侧
|
||||
// 均已配置同钥时自动激活,无需人工点击);上一轮未结束时本轮跳过(防堆积)。 // Logan.Li
|
||||
func (s *Service) StartSyncLoop(intervalMinutes int) {
|
||||
if intervalMinutes <= 0 {
|
||||
intervalMinutes = 10
|
||||
}
|
||||
go func() {
|
||||
ticker := time.NewTicker(time.Duration(intervalMinutes) * time.Minute)
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
var running int32
|
||||
runOnce := func() {
|
||||
if !atomic.CompareAndSwapInt32(&running, 0, 1) {
|
||||
return // 上一轮仍在进行,跳过本轮防堆积 // Logan.Li
|
||||
}
|
||||
defer atomic.StoreInt32(&running, 0)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Printf("[同步] 本轮异常恢复: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
var peers []model.PeerNode
|
||||
s.db.Where("status = ?", model.PeerStatusActive).Find(&peers)
|
||||
s.db.Where("status IN ?", []string{model.PeerStatusActive, model.PeerStatusPending}).Find(&peers)
|
||||
for _, peer := range peers {
|
||||
p := peer
|
||||
// pending 先尝试握手(对端未配置/密钥不一致时静默失败,下轮再试) // Logan.Li
|
||||
if p.Status == model.PeerStatusPending {
|
||||
if _, err := s.TestHandshake(p.ID); err != nil {
|
||||
continue
|
||||
}
|
||||
s.db.First(&p, p.ID)
|
||||
}
|
||||
if _, err := s.ExchangeOut(&p); err != nil {
|
||||
log.Printf("[同步] 节点 %s 本轮失败: %v", peer.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
runOnce() // 启动即先跑一轮,不等首个间隔 // Logan.Li
|
||||
ticker := time.NewTicker(time.Duration(intervalMinutes) * time.Minute)
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
runOnce()
|
||||
}
|
||||
}()
|
||||
log.Printf("[同步] 定时双向同步已启动(每 %d 分钟)", intervalMinutes)
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"backend/config"
|
||||
"backend/database"
|
||||
licenseservice "backend/internal/service/license"
|
||||
syncservice "backend/internal/service/sync"
|
||||
"backend/router"
|
||||
"context"
|
||||
"log"
|
||||
@@ -27,6 +28,9 @@ func main() {
|
||||
// 启动在线状态清扫(超时未心跳的激活记录置为离线) // Logan.Li
|
||||
licenseservice.StartOnlineSweeper(db, cfg.OnlineTTLMinutes)
|
||||
|
||||
// 启动节点定时双向同步(宽松节奏,默认 10 分钟) // Logan.Li
|
||||
syncservice.NewService(db, cfg).StartSyncLoop(cfg.SyncIntervalMinutes)
|
||||
|
||||
// 初始化路由 // Logan.Li
|
||||
r := router.SetupRouter(db, cfg)
|
||||
|
||||
|
||||
@@ -96,9 +96,6 @@ func SetupRouter(db *gorm.DB, cfg *config.Config) *gin.Engine {
|
||||
settingController := setting.NewSettingController(db)
|
||||
syncController := synccontroller.NewController(db, cfg)
|
||||
|
||||
// 启动节点定时双向同步(宽松节奏,默认 10 分钟) // Logan.Li
|
||||
syncController.Svc().StartSyncLoop(cfg.SyncIntervalMinutes)
|
||||
|
||||
api := r.Group("/api")
|
||||
{
|
||||
// ============ 节点互联(对端调用,HMAC 签名认证,非 JWT) ============
|
||||
|
||||
Reference in new issue
Block a user