仰望星辰工作室

clearlove2.1

clearlove2.1/ internal/plugin/scheduler.go 1.8 KB · 88 行 原始文件
1// 应用型插件定时任务调度。
2//
3// 每个任务一条 goroutine + Ticker,加载时启动、卸载时停止;
4// 触发走沙箱(超时、权限、审计),失败计入熔断。
5package plugin
6
7import (
8 "context"
9 "sync"
10 "time"
11
12 "clearlove/internal/util"
13)
14
15var (
16 jobMu sync.Mutex
17 jobStops = map[string]chan struct{}{} // dir -> stop
18)
19
20// startJobs 为插件的全部任务启动调度
21func startJobs(a *App) {
22 if a == nil || len(a.Jobs) == 0 {
23 return
24 }
25 stopJobs(a.Dir)
26 stop := make(chan struct{})
27 jobMu.Lock()
28 jobStops[a.Dir] = stop
29 jobMu.Unlock()
30
31 for _, j := range a.Jobs {
32 j := j
33 go func() {
34 ticker := time.NewTicker(j.Every)
35 defer ticker.Stop()
36 for {
37 select {
38 case <-stop:
39 return
40 case <-ticker.C:
41 runJob(a, j)
42 }
43 }
44 }()
45 }
46 util.Log("info", "插件 %s 已注册 %d 个定时任务", a.Plugin.SlugOf(), len(a.Jobs))
47}
48
49// stopJobs 停止插件的全部任务
50func stopJobs(dir string) {
51 jobMu.Lock()
52 stop, ok := jobStops[dir]
53 if ok {
54 delete(jobStops, dir)
55 }
56 jobMu.Unlock()
57 if ok {
58 close(stop)
59 }
60}
61
62func runJob(a *App, j JobReg) {
63 if a.Worker == nil || a.Worker.Closed() {
64 return
65 }
66 ctx, cancel := context.WithTimeout(context.Background(), a.Plugin.Timeout())
67 defer cancel()
68 start := time.Now()
69 _, err := a.Worker.Do(ctx, func(rt *jsRuntime) (any, error) {
70 rt.cur = nil
71 _, err := rt.callFn(j.Fn)
72 return nil, err
73 })
74 if err != nil {
75 noteFailure(a, err)
76 logPlugin(a.Plugin.SlugOf(), "job:"+j.Name, "执行失败: "+err.Error(), time.Since(start))
77 return
78 }
79 noteSuccess(a)
80 logPlugin(a.Plugin.SlugOf(), "job:"+j.Name, "执行完成", time.Since(start))
81}
82
83// JobCount 当前注册的任务数(后台展示用)
84func JobCount() int {
85 jobMu.Lock()
86 defer jobMu.Unlock()
87 return len(jobStops)
88}