2
2
// on the underlying queue.
3
3
//
4
4
// It provides:
5
- // - Limit on how many jobs can be run simultaneously
6
- // - Automatic message timeout extension while the job is running
7
- // - Graceful shutdown
5
+ // - Limit on how many jobs can be run simultaneously
6
+ // - Automatic message timeout extension while the job is running
7
+ // - Graceful shutdown
8
8
package jobs
9
9
10
10
import (
@@ -22,7 +22,12 @@ import (
22
22
"github.com/maragudk/goqite"
23
23
)
24
24
25
+ // NewRunnerOpts are options for [NewRunner].
26
+ // - [NewRunner.Extend] is by how much a job message timeout is extended each time while the job is running.
27
+ // - [NewRunnerOpts.Limit] is for how many jobs can be run simultaneously.
28
+ // - [NewRunner.PollInterval] is how often the runner polls the queue for new messages.
25
29
type NewRunnerOpts struct {
30
+ Extend time.Duration
26
31
Limit int
27
32
Log logger
28
33
PollInterval time.Duration
@@ -42,7 +47,12 @@ func NewRunner(opts NewRunnerOpts) *Runner {
42
47
opts .PollInterval = 100 * time .Millisecond
43
48
}
44
49
50
+ if opts .Extend == 0 {
51
+ opts .Extend = 5 * time .Second
52
+ }
53
+
45
54
return & Runner {
55
+ extend : opts .Extend ,
46
56
jobCountLimit : opts .Limit ,
47
57
jobs : make (map [string ]Func ),
48
58
log : opts .Log ,
@@ -52,6 +62,7 @@ func NewRunner(opts NewRunnerOpts) *Runner {
52
62
}
53
63
54
64
type Runner struct {
65
+ extend time.Duration
55
66
jobCount int
56
67
jobCountLimit int
57
68
jobCountLock sync.RWMutex
@@ -153,25 +164,24 @@ func (r *Runner) receiveAndRun(ctx context.Context, wg *sync.WaitGroup) {
153
164
defer cancel ()
154
165
155
166
// Extend the job message while the job is running
156
- done := make (chan struct {}, 1 )
157
- defer func () {
158
- done <- struct {}{}
159
- }()
160
-
161
167
go func () {
168
+ // Start by sleeping so we don't extend immediately
169
+ time .Sleep (r .extend - r .extend / 5 )
162
170
for {
163
171
select {
164
- case <- done :
172
+ case <- jobCtx . Done () :
165
173
return
166
174
default :
167
- if err := r .queue .Extend (jobCtx , m .ID , 5 * time .Second ); err != nil {
175
+ r .log .Info ("Extending message timeout" , "name" , jm .Name )
176
+ if err := r .queue .Extend (jobCtx , m .ID , r .extend ); err != nil {
168
177
r .log .Info ("Error extending message timeout" , "error" , err )
169
178
}
170
- time .Sleep (3 * time . Second )
179
+ time .Sleep (r . extend - r . extend / 5 )
171
180
}
172
181
}
173
182
}()
174
183
184
+ r .log .Info ("Running job" , "name" , jm .Name )
175
185
before := time .Now ()
176
186
if err := job (jobCtx , jm .Message ); err != nil {
177
187
r .log .Info ("Error running job" , "name" , jm .Name , "error" , err )
@@ -183,7 +193,7 @@ func (r *Runner) receiveAndRun(ctx context.Context, wg *sync.WaitGroup) {
183
193
deleteCtx , cancel := context .WithTimeout (context .Background (), time .Second )
184
194
defer cancel ()
185
195
if err := r .queue .Delete (deleteCtx , m .ID ); err != nil {
186
- r .log .Info ("Error deleting job from queue" , "error" , err )
196
+ r .log .Info ("Error deleting job from queue, it will be retried " , "error" , err )
187
197
}
188
198
}()
189
199
}
0 commit comments