mirror of
https://github.com/TeaOSLab/EdgeNode.git
synced 2025-11-07 18:50:27 +08:00
自动在空闲时间执行定时任务
This commit is contained in:
@@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
|
||||||
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/idles"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils/kvstore"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/kvstore"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -78,14 +78,15 @@ func (this *KVIPList) init() error {
|
|||||||
this.cleanTicker.Stop()
|
this.cleanTicker.Stop()
|
||||||
})
|
})
|
||||||
|
|
||||||
for range this.cleanTicker.C {
|
idles.RunTicker(this.cleanTicker, func() {
|
||||||
fsutils.WaitLoad(15, 16, 1*time.Hour)
|
if this.isClosed {
|
||||||
|
return
|
||||||
|
}
|
||||||
deleteErr := this.DeleteExpiredItems()
|
deleteErr := this.DeleteExpiredItems()
|
||||||
if deleteErr != nil {
|
if deleteErr != nil {
|
||||||
remotelogs.Error("IP_LIST_DB", "clean expired items failed: "+deleteErr.Error())
|
remotelogs.Error("IP_LIST_DB", "clean expired items failed: "+deleteErr.Error())
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils/dbs"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/dbs"
|
||||||
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/idles"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -167,14 +167,12 @@ ON "` + this.itemTableName + `" (
|
|||||||
this.cleanTicker.Stop()
|
this.cleanTicker.Stop()
|
||||||
})
|
})
|
||||||
|
|
||||||
for range this.cleanTicker.C {
|
idles.RunTicker(this.cleanTicker, func() {
|
||||||
fsutils.WaitLoad(15, 16, 1*time.Hour)
|
|
||||||
|
|
||||||
deleteErr := this.DeleteExpiredItems()
|
deleteErr := this.DeleteExpiredItems()
|
||||||
if deleteErr != nil {
|
if deleteErr != nil {
|
||||||
remotelogs.Error("IP_LIST_DB", "clean expired items failed: "+deleteErr.Error())
|
remotelogs.Error("IP_LIST_DB", "clean expired items failed: "+deleteErr.Error())
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/rpc"
|
"github.com/TeaOSLab/EdgeNode/internal/rpc"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/trackers"
|
"github.com/TeaOSLab/EdgeNode/internal/trackers"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/utils/idles"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/waf"
|
"github.com/TeaOSLab/EdgeNode/internal/waf"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/zero"
|
"github.com/TeaOSLab/EdgeNode/internal/zero"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
@@ -38,9 +39,9 @@ func init() {
|
|||||||
|
|
||||||
var ticker = time.NewTicker(24 * time.Hour)
|
var ticker = time.NewTicker(24 * time.Hour)
|
||||||
goman.New(func() {
|
goman.New(func() {
|
||||||
for range ticker.C {
|
idles.RunTicker(ticker, func() {
|
||||||
SharedIPListManager.DeleteExpiredItems()
|
SharedIPListManager.DeleteExpiredItems()
|
||||||
}
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeNode/internal/trackers"
|
"github.com/TeaOSLab/EdgeNode/internal/trackers"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
||||||
byteutils "github.com/TeaOSLab/EdgeNode/internal/utils/byte"
|
byteutils "github.com/TeaOSLab/EdgeNode/internal/utils/byte"
|
||||||
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/idles"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils/kvstore"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/kvstore"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/zero"
|
"github.com/TeaOSLab/EdgeNode/internal/zero"
|
||||||
"github.com/cockroachdb/pebble"
|
"github.com/cockroachdb/pebble"
|
||||||
@@ -37,7 +37,7 @@ type KVTask struct {
|
|||||||
serverIdMapLocker sync.Mutex
|
serverIdMapLocker sync.Mutex
|
||||||
|
|
||||||
statsTicker *utils.Ticker
|
statsTicker *utils.Ticker
|
||||||
cleanTicker *utils.Ticker
|
cleanTicker *time.Ticker
|
||||||
uploadTicker *utils.Ticker
|
uploadTicker *utils.Ticker
|
||||||
|
|
||||||
valuesCacheMap map[string]int64 // hash => value
|
valuesCacheMap map[string]int64 // hash => value
|
||||||
@@ -285,18 +285,16 @@ func (this *KVTask) Start() error {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 清理
|
// 清理
|
||||||
this.cleanTicker = utils.NewTicker(24 * time.Hour)
|
this.cleanTicker = time.NewTicker(24 * time.Hour)
|
||||||
goman.New(func() {
|
goman.New(func() {
|
||||||
for this.cleanTicker.Next() {
|
idles.RunTicker(this.cleanTicker, func() {
|
||||||
fsutils.WaitLoad(15, 16, 1*time.Hour)
|
|
||||||
|
|
||||||
var tr = trackers.Begin("METRIC:CLEAN_EXPIRED")
|
var tr = trackers.Begin("METRIC:CLEAN_EXPIRED")
|
||||||
err := this.CleanExpired()
|
err := this.CleanExpired()
|
||||||
tr.End()
|
tr.End()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
remotelogs.Error("METRIC", "clean expired stats failed: "+err.Error())
|
remotelogs.Error("METRIC", "clean expired stats failed: "+err.Error())
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// 上传
|
// 上传
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeNode/internal/trackers"
|
"github.com/TeaOSLab/EdgeNode/internal/trackers"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils/dbs"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/dbs"
|
||||||
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/idles"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/zero"
|
"github.com/TeaOSLab/EdgeNode/internal/zero"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
@@ -42,7 +42,7 @@ type SQLiteTask struct {
|
|||||||
db *dbs.DB
|
db *dbs.DB
|
||||||
statTableName string
|
statTableName string
|
||||||
|
|
||||||
cleanTicker *utils.Ticker
|
cleanTicker *time.Ticker
|
||||||
uploadTicker *utils.Ticker
|
uploadTicker *utils.Ticker
|
||||||
|
|
||||||
cleanVersion int32
|
cleanVersion int32
|
||||||
@@ -207,18 +207,16 @@ func (this *SQLiteTask) Start() error {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 清理
|
// 清理
|
||||||
this.cleanTicker = utils.NewTicker(24 * time.Hour)
|
this.cleanTicker = time.NewTicker(24 * time.Hour)
|
||||||
goman.New(func() {
|
goman.New(func() {
|
||||||
for this.cleanTicker.Next() {
|
idles.RunTicker(this.cleanTicker, func() {
|
||||||
fsutils.WaitLoad(15, 16, 1*time.Hour)
|
|
||||||
|
|
||||||
var tr = trackers.Begin("METRIC:CLEAN_EXPIRED")
|
var tr = trackers.Begin("METRIC:CLEAN_EXPIRED")
|
||||||
err := this.CleanExpired()
|
err := this.CleanExpired()
|
||||||
tr.End()
|
tr.End()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
remotelogs.Error("METRIC", "clean expired stats failed: "+err.Error())
|
remotelogs.Error("METRIC", "clean expired stats failed: "+err.Error())
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// 上传
|
// 上传
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
||||||
executils "github.com/TeaOSLab/EdgeNode/internal/utils/exec"
|
executils "github.com/TeaOSLab/EdgeNode/internal/utils/exec"
|
||||||
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/idles"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -29,16 +29,13 @@ func (this *TrimDisksTask) Start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ticker = time.NewTicker(2 * 24 * time.Hour) // every 2 days
|
var ticker = time.NewTicker(2 * 24 * time.Hour) // every 2 days
|
||||||
for range ticker.C {
|
idles.RunTicker(ticker, func() {
|
||||||
// prevent system overload
|
|
||||||
fsutils.WaitLoad(15, 24, 1*time.Hour)
|
|
||||||
|
|
||||||
// run the task
|
// run the task
|
||||||
err = this.loop()
|
err = this.loop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
remotelogs.Warn("TRIM_DISKS", "trim disks failed: "+err.Error())
|
remotelogs.Warn("TRIM_DISKS", "trim disks failed: "+err.Error())
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// run the task once
|
// run the task once
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/trackers"
|
"github.com/TeaOSLab/EdgeNode/internal/trackers"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
|
||||||
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/idles"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils/kvstore"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/kvstore"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
@@ -87,14 +87,12 @@ func (this *DAUManager) Init() error {
|
|||||||
|
|
||||||
// clean expires items
|
// clean expires items
|
||||||
goman.New(func() {
|
goman.New(func() {
|
||||||
for range this.cleanTicker.C {
|
idles.RunTicker(this.cleanTicker, func() {
|
||||||
fsutils.WaitLoad(15, 16, 1*time.Hour)
|
|
||||||
|
|
||||||
err := this.CleanStats()
|
err := this.CleanStats()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
remotelogs.Error("DAU_MANAGER", "clean stats failed: "+err.Error())
|
remotelogs.Error("DAU_MANAGER", "clean stats failed: "+err.Error())
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// dump ip to kvstore
|
// dump ip to kvstore
|
||||||
@@ -208,6 +206,8 @@ func (this *DAUManager) TestInspect(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *DAUManager) Close() error {
|
func (this *DAUManager) Close() error {
|
||||||
|
this.cleanTicker.Stop()
|
||||||
|
|
||||||
this.statLocker.Lock()
|
this.statLocker.Lock()
|
||||||
var statMap = this.statMap
|
var statMap = this.statMap
|
||||||
this.statMap = map[string]int64{}
|
this.statMap = map[string]int64{}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package cachehits
|
|||||||
import (
|
import (
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/utils/idles"
|
||||||
memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem"
|
memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -58,7 +59,7 @@ func NewStat(goodRatio uint64) *Stat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *Stat) init() {
|
func (this *Stat) init() {
|
||||||
for range this.ticker.C {
|
idles.RunTicker(this.ticker, func() {
|
||||||
var currentTime = fasttime.Now().Unix()
|
var currentTime = fasttime.Now().Unix()
|
||||||
|
|
||||||
this.mu.RLock()
|
this.mu.RLock()
|
||||||
@@ -73,7 +74,7 @@ func (this *Stat) init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.mu.RUnlock()
|
this.mu.RUnlock()
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *Stat) IncreaseCached(category string) {
|
func (this *Stat) IncreaseCached(category string) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
package counters
|
package counters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
|
||||||
memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem"
|
memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem"
|
||||||
syncutils "github.com/TeaOSLab/EdgeNode/internal/utils/sync"
|
syncutils "github.com/TeaOSLab/EdgeNode/internal/utils/sync"
|
||||||
@@ -56,11 +57,11 @@ func (this *Counter[T]) WithGC() *Counter[T] {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
this.gcTicker = time.NewTicker(1 * time.Second)
|
this.gcTicker = time.NewTicker(1 * time.Second)
|
||||||
go func() {
|
goman.New(func() {
|
||||||
for range this.gcTicker.C {
|
for range this.gcTicker.C {
|
||||||
this.GC()
|
this.GC()
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package fsutils
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
|
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
"github.com/shirou/gopsutil/v3/load"
|
"github.com/shirou/gopsutil/v3/load"
|
||||||
"os"
|
"os"
|
||||||
@@ -55,7 +56,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// test disk
|
// test disk
|
||||||
go func() {
|
goman.New(func() {
|
||||||
// load last result from local disk
|
// load last result from local disk
|
||||||
cacheData, cacheErr := os.ReadFile(Tea.Root + "/data/" + diskSpeedDataFile)
|
cacheData, cacheErr := os.ReadFile(Tea.Root + "/data/" + diskSpeedDataFile)
|
||||||
if cacheErr == nil {
|
if cacheErr == nil {
|
||||||
@@ -83,17 +84,17 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
|
|
||||||
// check high load
|
// check high load
|
||||||
go func() {
|
goman.New(func() {
|
||||||
var ticker = time.NewTicker(5 * time.Second)
|
var ticker = time.NewTicker(5 * time.Second)
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
stat, _ := load.Avg()
|
stat, _ := load.Avg()
|
||||||
IsInExtremelyHighLoad = stat != nil && stat.Load1 > extremelyHighLoad1Threshold
|
IsInExtremelyHighLoad = stat != nil && stat.Load1 > extremelyHighLoad1Threshold
|
||||||
IsInHighLoad = stat != nil && stat.Load1 > highLoad1Threshold && !DiskIsFast()
|
IsInHighLoad = stat != nil && stat.Load1 > highLoad1Threshold && !DiskIsFast()
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func DiskIsFast() bool {
|
func DiskIsFast() bool {
|
||||||
@@ -145,8 +146,12 @@ func calculateDiskMaxWrites() {
|
|||||||
func WaitLoad(maxLoad float64, maxLoops int, delay time.Duration) {
|
func WaitLoad(maxLoad float64, maxLoops int, delay time.Duration) {
|
||||||
for i := 0; i < maxLoops; i++ {
|
for i := 0; i < maxLoops; i++ {
|
||||||
stat, err := load.Avg()
|
stat, err := load.Avg()
|
||||||
if err == nil && stat.Load1 > maxLoad {
|
if err == nil {
|
||||||
|
if stat.Load1 > maxLoad {
|
||||||
time.Sleep(delay)
|
time.Sleep(delay)
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func TestWrites(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWaitLoad(t *testing.T) {
|
func TestWaitLoad(t *testing.T) {
|
||||||
fsutils.WaitLoad(100, 1, 1 * time.Minute)
|
fsutils.WaitLoad(100, 5, 1*time.Minute)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkWrites(b *testing.B) {
|
func BenchmarkWrites(b *testing.B) {
|
||||||
|
|||||||
128
internal/utils/idles/run.go
Normal file
128
internal/utils/idles/run.go
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package idles
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
||||||
|
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
|
||||||
|
"github.com/iwind/TeaGo/Tea"
|
||||||
|
"github.com/shirou/gopsutil/v3/load"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxSamples = 7
|
||||||
|
const cacheFile = "idles.cache"
|
||||||
|
|
||||||
|
var hourlyLoadMap = map[int]*HourlyLoad{}
|
||||||
|
var minLoadHour = -1
|
||||||
|
|
||||||
|
type HourlyLoad struct {
|
||||||
|
Hour int `json:"hour"`
|
||||||
|
Avg float64 `json:"avg"`
|
||||||
|
Values []float64 `json:"values"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if !teaconst.IsMain {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// recover from cache
|
||||||
|
{
|
||||||
|
data, err := os.ReadFile(Tea.Root + "/data/" + cacheFile)
|
||||||
|
if err == nil {
|
||||||
|
_ = json.Unmarshal(data, &hourlyLoadMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
goman.New(func() {
|
||||||
|
var ticker = time.NewTicker(1 * time.Hour)
|
||||||
|
for range ticker.C {
|
||||||
|
CheckHourlyLoad(time.Now().Hour())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckHourlyLoad(hour int) {
|
||||||
|
avgLoad, err := load.Avg()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
hourlyLoad, ok := hourlyLoadMap[hour]
|
||||||
|
if !ok {
|
||||||
|
hourlyLoad = &HourlyLoad{
|
||||||
|
Hour: hour,
|
||||||
|
}
|
||||||
|
hourlyLoadMap[hour] = hourlyLoad
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(hourlyLoad.Values) >= maxSamples {
|
||||||
|
hourlyLoad.Values = hourlyLoad.Values[:maxSamples-1]
|
||||||
|
}
|
||||||
|
hourlyLoad.Values = append(hourlyLoad.Values, avgLoad.Load15)
|
||||||
|
|
||||||
|
var sum float64
|
||||||
|
for _, v := range hourlyLoad.Values {
|
||||||
|
sum += v
|
||||||
|
}
|
||||||
|
hourlyLoad.Avg = sum / float64(len(hourlyLoad.Values))
|
||||||
|
|
||||||
|
// calculate min load hour
|
||||||
|
var allLoads = []*HourlyLoad{}
|
||||||
|
for _, v := range hourlyLoadMap {
|
||||||
|
allLoads = append(allLoads, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(allLoads, func(i, j int) bool {
|
||||||
|
return allLoads[i].Avg < allLoads[j].Avg
|
||||||
|
})
|
||||||
|
|
||||||
|
minLoadHour = allLoads[0].Hour
|
||||||
|
|
||||||
|
// write to cache
|
||||||
|
hourlyLoadMapJSON, err := json.Marshal(hourlyLoadMap)
|
||||||
|
if err == nil {
|
||||||
|
_ = os.WriteFile(Tea.Root+"/data/"+cacheFile, hourlyLoadMapJSON, 0666)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Run(f func()) {
|
||||||
|
defer f()
|
||||||
|
|
||||||
|
if minLoadHour < 0 {
|
||||||
|
fsutils.WaitLoad(15, 8, time.Hour)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var hour = time.Now().Hour()
|
||||||
|
if minLoadHour == hour {
|
||||||
|
fsutils.WaitLoad(15, 10, time.Minute)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if minLoadHour < hour {
|
||||||
|
time.Sleep(time.Duration(24-hour+minLoadHour) * time.Hour)
|
||||||
|
} else {
|
||||||
|
time.Sleep(time.Duration(minLoadHour-hour) * time.Hour)
|
||||||
|
}
|
||||||
|
fsutils.WaitLoad(15, 10, time.Minute)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunTicker(ticker *time.Ticker, f func()) {
|
||||||
|
for range ticker.C {
|
||||||
|
Run(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMinLoadHour() int {
|
||||||
|
return minLoadHour
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHourlyLoadMap() map[int]*HourlyLoad {
|
||||||
|
return hourlyLoadMap
|
||||||
|
}
|
||||||
41
internal/utils/idles/run_test.go
Normal file
41
internal/utils/idles/run_test.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package idles_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/utils/idles"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
|
||||||
|
"github.com/iwind/TeaGo/logs"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCheckHourlyLoad(t *testing.T) {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
idles.CheckHourlyLoad(1)
|
||||||
|
idles.CheckHourlyLoad(2)
|
||||||
|
idles.CheckHourlyLoad(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log(idles.TestMinLoadHour())
|
||||||
|
logs.PrintAsJSON(idles.TestHourlyLoadMap(), t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRun(t *testing.T) {
|
||||||
|
//idles.CheckHourlyLoad(time.Now().Hour())
|
||||||
|
idles.Run(func() {
|
||||||
|
t.Log("run once")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunTicker(t *testing.T) {
|
||||||
|
if !testutils.IsSingleTesting() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var ticker = time.NewTicker(10 * time.Second)
|
||||||
|
idles.RunTicker(ticker, func() {
|
||||||
|
t.Log(timeutil.Format("H:i:s"), "run once")
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user