-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjobs.go
More file actions
113 lines (96 loc) · 2.16 KB
/
Copy pathjobs.go
File metadata and controls
113 lines (96 loc) · 2.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package cartridge
import (
"context"
"sync"
"time"
"gorm.io/gorm"
)
// JobContext provides job-scoped access to application dependencies.
type JobContext struct {
context.Context
Logger Logger
DB *gorm.DB
}
// Processor defines the interface for processing a batch of work.
type Processor interface {
ProcessBatch(ctx *JobContext) error
}
// JobDispatcher runs processors periodically in a background loop.
type JobDispatcher struct {
logger Logger
dbManager DBManager
processors []Processor
interval time.Duration
mu sync.Mutex
running bool
stop chan struct{}
wg sync.WaitGroup
}
// NewJobDispatcher creates a new background job dispatcher.
func NewJobDispatcher(logger Logger, dbManager DBManager, interval time.Duration, processors ...Processor) *JobDispatcher {
return &JobDispatcher{
logger: logger,
dbManager: dbManager,
processors: processors,
interval: interval,
}
}
// Start begins the background processing loop.
func (d *JobDispatcher) Start() error {
d.mu.Lock()
defer d.mu.Unlock()
if d.running {
return nil
}
d.stop = make(chan struct{})
d.running = true
d.wg.Add(1)
go d.loop()
return nil
}
// Stop terminates the dispatcher and waits for completion.
func (d *JobDispatcher) Stop() {
d.mu.Lock()
if !d.running {
d.mu.Unlock()
return
}
close(d.stop)
d.running = false
d.mu.Unlock()
d.wg.Wait()
}
func (d *JobDispatcher) loop() {
defer d.wg.Done()
d.logger.Info("jobs dispatcher started", "processors", len(d.processors))
ticker := time.NewTicker(d.interval)
defer ticker.Stop()
// Run immediately on startup
d.processBatch()
for {
select {
case <-ticker.C:
d.processBatch()
case <-d.stop:
d.logger.Info("jobs dispatcher stopped")
return
}
}
}
func (d *JobDispatcher) processBatch() {
db, err := d.dbManager.Connect()
if err != nil {
d.logger.Error("failed to connect to database", "error", err)
return
}
ctx := &JobContext{
Context: context.Background(),
Logger: d.logger,
DB: db,
}
for _, processor := range d.processors {
if err := processor.ProcessBatch(ctx); err != nil {
d.logger.Error("processor failed", "error", err)
}
}
}