mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-15 15:50:59 +00:00
refactor(web): centralize background job cadences (#5269)
This commit is contained in:
@@ -0,0 +1,34 @@
|
|||||||
|
package web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/robfig/cron/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// All centralized background-job cadences must remain valid cron specs. This is
|
||||||
|
// the guard for the "single tuning surface" refactor: editing a cadence to an
|
||||||
|
// invalid spec fails here instead of silently dropping a job at startup.
|
||||||
|
//
|
||||||
|
// NOTE: package web embeds the built frontend (//go:embed all:dist), so this
|
||||||
|
// test compiles only after `npm run build` has populated web/dist — the normal
|
||||||
|
// repo build flow.
|
||||||
|
func TestJobCadencesAreValidCronSpecs(t *testing.T) {
|
||||||
|
cadences := map[string]string{
|
||||||
|
"cadenceXrayRunning": cadenceXrayRunning,
|
||||||
|
"cadenceXrayRestart": cadenceXrayRestart,
|
||||||
|
"cadenceXrayTraffic": cadenceXrayTraffic,
|
||||||
|
"cadenceMtproto": cadenceMtproto,
|
||||||
|
"cadenceClientIPScan": cadenceClientIPScan,
|
||||||
|
"cadenceNodeHeartbeat": cadenceNodeHeartbeat,
|
||||||
|
"cadenceNodeTraffic": cadenceNodeTraffic,
|
||||||
|
"cadenceOutboundSub": cadenceOutboundSub,
|
||||||
|
"cadenceCheckHash": cadenceCheckHash,
|
||||||
|
"cadenceCPUAlarm": cadenceCPUAlarm,
|
||||||
|
}
|
||||||
|
for name, spec := range cadences {
|
||||||
|
if _, err := cron.ParseStandard(spec); err != nil {
|
||||||
|
t.Errorf("%s = %q is not a valid cron spec: %v", name, spec, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+29
-10
@@ -252,6 +252,25 @@ func (s *Server) initRouter() (*gin.Engine, error) {
|
|||||||
return engine, nil
|
return engine, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Background-job cadences. Centralized here as the single tuning surface; the
|
||||||
|
// values are unchanged from the historical hardcoded cron specs. Follow-up:
|
||||||
|
// make these configurable via settings, add per-tick jitter to de-synchronize
|
||||||
|
// fleet load, skip expensive jobs when no WebSocket clients are connected or
|
||||||
|
// node/xray state is unchanged, and export per-job duration/skipped/error
|
||||||
|
// counters.
|
||||||
|
const (
|
||||||
|
cadenceXrayRunning = "@every 1s"
|
||||||
|
cadenceXrayRestart = "@every 30s"
|
||||||
|
cadenceXrayTraffic = "@every 5s"
|
||||||
|
cadenceMtproto = "@every 10s"
|
||||||
|
cadenceClientIPScan = "@every 10s"
|
||||||
|
cadenceNodeHeartbeat = "@every 5s"
|
||||||
|
cadenceNodeTraffic = "@every 5s"
|
||||||
|
cadenceOutboundSub = "@every 5m"
|
||||||
|
cadenceCheckHash = "@every 2m"
|
||||||
|
cadenceCPUAlarm = "@every 10s"
|
||||||
|
)
|
||||||
|
|
||||||
// startTask schedules background jobs (Xray checks, traffic jobs, cron
|
// startTask schedules background jobs (Xray checks, traffic jobs, cron
|
||||||
// jobs) which the panel relies on for periodic maintenance and monitoring.
|
// jobs) which the panel relies on for periodic maintenance and monitoring.
|
||||||
func (s *Server) startTask(restartXray bool) {
|
func (s *Server) startTask(restartXray bool) {
|
||||||
@@ -262,10 +281,10 @@ func (s *Server) startTask(restartXray bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check whether xray is running every second
|
// Check whether xray is running every second
|
||||||
s.cron.AddJob("@every 1s", job.NewCheckXrayRunningJob())
|
s.cron.AddJob(cadenceXrayRunning, job.NewCheckXrayRunningJob())
|
||||||
|
|
||||||
// Check if xray needs to be restarted every 30 seconds
|
// Check if xray needs to be restarted every 30 seconds
|
||||||
s.cron.AddFunc("@every 30s", func() {
|
s.cron.AddFunc(cadenceXrayRestart, func() {
|
||||||
if s.xrayService.IsNeedRestartAndSetFalse() {
|
if s.xrayService.IsNeedRestartAndSetFalse() {
|
||||||
err := s.xrayService.RestartXray(false)
|
err := s.xrayService.RestartXray(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -276,23 +295,23 @@ func (s *Server) startTask(restartXray bool) {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(time.Second * 5)
|
time.Sleep(time.Second * 5)
|
||||||
s.cron.AddJob("@every 5s", job.NewXrayTrafficJob())
|
s.cron.AddJob(cadenceXrayTraffic, job.NewXrayTrafficJob())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Reconcile mtproto (mtg) sidecars and scrape their traffic
|
// Reconcile mtproto (mtg) sidecars and scrape their traffic
|
||||||
mtJob := job.NewMtprotoJob()
|
mtJob := job.NewMtprotoJob()
|
||||||
s.cron.AddJob("@every 10s", mtJob)
|
s.cron.AddJob(cadenceMtproto, mtJob)
|
||||||
go mtJob.Run()
|
go mtJob.Run()
|
||||||
|
|
||||||
// check client ips from log file every 10 sec
|
// check client ips from log file every 10 sec
|
||||||
s.cron.AddJob("@every 10s", job.NewCheckClientIpJob())
|
s.cron.AddJob(cadenceClientIPScan, job.NewCheckClientIpJob())
|
||||||
|
|
||||||
s.cron.AddJob("@every 5s", job.NewNodeHeartbeatJob())
|
s.cron.AddJob(cadenceNodeHeartbeat, job.NewNodeHeartbeatJob())
|
||||||
|
|
||||||
s.cron.AddJob("@every 5s", job.NewNodeTrafficSyncJob())
|
s.cron.AddJob(cadenceNodeTraffic, job.NewNodeTrafficSyncJob())
|
||||||
|
|
||||||
// Outbound subscription auto-refresh (respects per-sub updateInterval)
|
// Outbound subscription auto-refresh (respects per-sub updateInterval)
|
||||||
s.cron.AddJob("@every 5m", job.NewOutboundSubscriptionJob())
|
s.cron.AddJob(cadenceOutboundSub, job.NewOutboundSubscriptionJob())
|
||||||
|
|
||||||
// check client ips from log file every day
|
// check client ips from log file every day
|
||||||
s.cron.AddJob("@daily", job.NewClearLogsJob())
|
s.cron.AddJob("@daily", job.NewClearLogsJob())
|
||||||
@@ -339,12 +358,12 @@ func (s *Server) startTask(restartXray bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for Telegram bot callback query hash storage reset
|
// check for Telegram bot callback query hash storage reset
|
||||||
s.cron.AddJob("@every 2m", job.NewCheckHashStorageJob())
|
s.cron.AddJob(cadenceCheckHash, job.NewCheckHashStorageJob())
|
||||||
|
|
||||||
// Check CPU load and alarm to TgBot if threshold passes
|
// Check CPU load and alarm to TgBot if threshold passes
|
||||||
cpuThreshold, err := s.settingService.GetTgCpu()
|
cpuThreshold, err := s.settingService.GetTgCpu()
|
||||||
if (err == nil) && (cpuThreshold > 0) {
|
if (err == nil) && (cpuThreshold > 0) {
|
||||||
s.cron.AddJob("@every 10s", job.NewCheckCpuJob())
|
s.cron.AddJob(cadenceCPUAlarm, job.NewCheckCpuJob())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s.cron.Remove(entry)
|
s.cron.Remove(entry)
|
||||||
|
|||||||
Reference in New Issue
Block a user