142 lines
2.7 KiB
Go
142 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"log/slog"
|
|
"net/http"
|
|
"platform/pkg/env"
|
|
"platform/pkg/logs"
|
|
"platform/pkg/rds"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
func main() {
|
|
Start()
|
|
}
|
|
|
|
var taskList = make(map[string]func(ctx context.Context, curr time.Time) error)
|
|
|
|
func Start() {
|
|
ctx := context.Background()
|
|
|
|
env.Init()
|
|
logs.Init()
|
|
rds.Init()
|
|
|
|
taskList["stopChannels"] = stopChannels
|
|
|
|
ticker := time.NewTicker(time.Second)
|
|
defer ticker.Stop()
|
|
|
|
// 互斥锁确保同一时间只有一个协程运行
|
|
// 如果之前的 tick 操作未完成,则跳过当前 tick
|
|
var mutex = &sync.Mutex{}
|
|
for curr := range ticker.C {
|
|
if mutex.TryLock() {
|
|
err := process(ctx, curr)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
mutex.Unlock()
|
|
} else {
|
|
slog.Warn("skip tick", slog.String("tick", curr.Format("2006-01-02 15:04:05")))
|
|
}
|
|
}
|
|
}
|
|
|
|
func process(ctx context.Context, curr time.Time) error {
|
|
|
|
// todo 异步化
|
|
for name, task := range taskList {
|
|
err := task(ctx, curr)
|
|
if err != nil {
|
|
slog.Error("task failed", slog.String("task", name), slog.String("error", err.Error()))
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func stopChannels(ctx context.Context, curr time.Time) error {
|
|
|
|
// 获取并删除
|
|
script := redis.NewScript(`
|
|
local result = redis.call('ZRANGEBYSCORE', KEYS[1], 0, ARGV[1])
|
|
if #result > 0 then
|
|
redis.call('ZREMRANGEBYSCORE', KEYS[1], 0, ARGV[1])
|
|
end
|
|
return result
|
|
`)
|
|
|
|
// 执行脚本
|
|
result, err := script.Run(ctx, rds.Client, []string{"tasks:channel"}, curr.Unix()).Result()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 处理结果
|
|
list, ok := result.([]any)
|
|
if !ok {
|
|
return errors.New("failed to convert result to []string")
|
|
}
|
|
var ids = make([]int, len(list))
|
|
for i, item := range list {
|
|
idStr, ok := item.(string)
|
|
if !ok {
|
|
slog.Debug(reflect.TypeOf(item).String())
|
|
return errors.New("failed to convert item to string")
|
|
}
|
|
id, err := strconv.Atoi(idStr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ids[i] = id
|
|
}
|
|
if len(ids) == 0 {
|
|
return nil
|
|
}
|
|
|
|
var body = map[string]any{
|
|
"by_ids": ids,
|
|
}
|
|
bodyStr, err := json.Marshal(body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
req, err := http.NewRequest(
|
|
http.MethodPost,
|
|
"http://localhost:8080/api/channel/remove", // todo 环境变量获取服务地址
|
|
strings.NewReader(string(bodyStr)),
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.SetBasicAuth("tasks", "tasks")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return errors.New("failed to stop channels: " + string(body))
|
|
}
|
|
|
|
return nil
|
|
}
|