7
7
"github.com/semaphoreui/semaphore/pkg/tz"
8
8
"github.com/semaphoreui/semaphore/services/tasks/stage_parsers"
9
9
"regexp"
10
+ "slices"
10
11
"strconv"
11
12
"strings"
12
13
"time"
@@ -25,9 +26,18 @@ type logRecord struct {
25
26
time time.Time
26
27
}
27
28
28
- type resourceLock struct {
29
- lock bool
30
- holder * TaskRunner
29
+ type EventType uint
30
+
31
+ const (
32
+ EventTypeNew EventType = 0
33
+ EventTypeFinished EventType = 1
34
+ EventTypeFailed EventType = 2
35
+ EventTypeEmpty EventType = 3
36
+ )
37
+
38
+ type PoolEvent struct {
39
+ eventType EventType
40
+ task * TaskRunner
31
41
}
32
42
33
43
type TaskPool struct {
@@ -48,7 +58,7 @@ type TaskPool struct {
48
58
49
59
store db.Store
50
60
51
- resourceLocker chan * resourceLock
61
+ queueEvents chan PoolEvent
52
62
53
63
aliases map [string ]* TaskRunner
54
64
}
@@ -214,41 +224,10 @@ func (p *TaskPool) Run() {
214
224
ticker := time .NewTicker (5 * time .Second )
215
225
216
226
defer func () {
217
- close (p .resourceLocker )
218
227
ticker .Stop ()
219
228
}()
220
229
221
- // Lock or unlock resources when running a TaskRunner
222
- go func (locker <- chan * resourceLock ) {
223
- for l := range locker {
224
- t := l .holder
225
-
226
- if l .lock {
227
- if p .blocks (t ) {
228
- panic ("Trying to lock an already locked resource!" )
229
- }
230
-
231
- projTasks , ok := p .activeProj [t .Task .ProjectID ]
232
- if ! ok {
233
- projTasks = make (map [int ]* TaskRunner )
234
- p .activeProj [t .Task .ProjectID ] = projTasks
235
- }
236
- projTasks [t .Task .ID ] = t
237
- p .RunningTasks [t .Task .ID ] = t
238
- continue
239
- }
240
-
241
- if p .activeProj [t .Task .ProjectID ] != nil && p .activeProj [t .Task .ProjectID ][t .Task .ID ] != nil {
242
- delete (p .activeProj [t .Task .ProjectID ], t .Task .ID )
243
- if len (p .activeProj [t .Task .ProjectID ]) == 0 {
244
- delete (p .activeProj , t .Task .ProjectID )
245
- }
246
- }
247
-
248
- delete (p .RunningTasks , t .Task .ID )
249
- delete (p .aliases , t .Alias )
250
- }
251
- }(p .resourceLocker )
230
+ go p .handleQueue ()
252
231
253
232
for {
254
233
select {
@@ -290,43 +269,87 @@ func (p *TaskPool) Run() {
290
269
case task := <- p .register : // new task created by API or schedule
291
270
292
271
db .StoreSession (p .store , "new task" , func () {
293
- p .Queue = append (p .Queue , task )
272
+ // p.Queue = append(p.Queue, task)
294
273
log .Debug (task )
295
274
msg := "Task " + strconv .Itoa (task .Task .ID ) + " added to queue"
296
275
task .Log (msg )
297
276
log .Info (msg )
298
277
task .saveStatus ()
299
278
})
279
+ p .queueEvents <- PoolEvent {EventTypeNew , task }
300
280
301
281
case <- ticker .C : // timer 5 seconds
302
- if len (p .Queue ) == 0 {
303
- break
304
- }
282
+ p .queueEvents <- PoolEvent {EventTypeEmpty , nil }
283
+
284
+ }
285
+ }
286
+ }
305
287
306
- //get TaskRunner from top of queue
307
- t := p .Queue [0 ]
308
- if t .Task .Status == task_logger .TaskFailStatus {
288
+ func (p * TaskPool ) handleQueue () {
289
+ for t := range p .queueEvents {
290
+ switch t .eventType {
291
+ case EventTypeNew :
292
+ p .Queue = append (p .Queue , t .task )
293
+ case EventTypeFinished :
294
+ p .onTaskStop (t .task )
295
+ }
296
+
297
+ if len (p .Queue ) == 0 {
298
+ continue
299
+ }
300
+
301
+ var i = 0
302
+ for i < len (p .Queue ) {
303
+ curr := p .Queue [i ]
304
+
305
+ if curr .Task .Status == task_logger .TaskFailStatus {
309
306
//delete failed TaskRunner from queue
310
- p .Queue = p .Queue [ 1 :]
311
- log .Info ("Task " + strconv .Itoa (t .Task .ID ) + " removed from queue" )
312
- break
307
+ p .Queue = slices . Delete ( p .Queue , i , i + 1 )
308
+ log .Info ("Task " + strconv .Itoa (curr .Task .ID ) + " removed from queue" )
309
+ continue
313
310
}
314
311
315
- if p .blocks (t ) {
316
- //move blocked TaskRunner to end of queue
317
- p .Queue = append (p .Queue [1 :], t )
318
- break
312
+ if p .blocks (curr ) {
313
+ i = i + 1
314
+ continue
319
315
}
320
316
321
- log .Info ("Set resource locker with TaskRunner " + strconv .Itoa (t .Task .ID ))
322
- p .resourceLocker <- & resourceLock {lock : true , holder : t }
317
+ p .Queue = slices .Delete (p .Queue , i , i + 1 )
318
+ runTask (curr , p )
319
+ }
320
+ }
321
+ }
322
+
323
+ func runTask (task * TaskRunner , p * TaskPool ) {
324
+ log .Info ("Set resource locker with TaskRunner " + strconv .Itoa (task .Task .ID ))
325
+
326
+ p .onTaskRun (task )
323
327
324
- go t .run ()
328
+ log .Info ("Task " + strconv .Itoa (task .Task .ID ) + " started" )
329
+ go task .run ()
330
+ }
325
331
326
- p .Queue = p .Queue [1 :]
327
- log .Info ("Task " + strconv .Itoa (t .Task .ID ) + " removed from queue" )
332
+ func (p * TaskPool ) onTaskRun (t * TaskRunner ) {
333
+ projTasks , ok := p .activeProj [t .Task .ProjectID ]
334
+ if ! ok {
335
+ projTasks = make (map [int ]* TaskRunner )
336
+ p .activeProj [t .Task .ProjectID ] = projTasks
337
+ }
338
+ projTasks [t .Task .ID ] = t
339
+ p .RunningTasks [t .Task .ID ] = t
340
+ p .aliases [t .Alias ] = t
341
+ }
342
+
343
+ func (p * TaskPool ) onTaskStop (t * TaskRunner ) {
344
+ if p .activeProj [t .Task .ProjectID ] != nil && p .activeProj [t .Task .ProjectID ][t .Task .ID ] != nil {
345
+ delete (p .activeProj [t .Task .ProjectID ], t .Task .ID )
346
+ if len (p .activeProj [t .Task .ProjectID ]) == 0 {
347
+ delete (p .activeProj , t .Task .ProjectID )
328
348
}
329
349
}
350
+
351
+ delete (p .RunningTasks , t .Task .ID )
352
+ delete (p .aliases , t .Alias )
330
353
}
331
354
332
355
func (p * TaskPool ) blocks (t * TaskRunner ) bool {
@@ -366,14 +389,14 @@ func (p *TaskPool) blocks(t *TaskRunner) bool {
366
389
367
390
func CreateTaskPool (store db.Store ) TaskPool {
368
391
return TaskPool {
369
- Queue : make ([]* TaskRunner , 0 ), // queue of waiting tasks
370
- register : make (chan * TaskRunner ), // add TaskRunner to queue
371
- activeProj : make (map [int ]map [int ]* TaskRunner ),
372
- RunningTasks : make (map [int ]* TaskRunner ), // working tasks
373
- logger : make (chan logRecord , 10000 ), // store log records to database
374
- store : store ,
375
- resourceLocker : make (chan * resourceLock ),
376
- aliases : make (map [string ]* TaskRunner ),
392
+ Queue : make ([]* TaskRunner , 0 ), // queue of waiting tasks
393
+ register : make (chan * TaskRunner ), // add TaskRunner to queue
394
+ activeProj : make (map [int ]map [int ]* TaskRunner ),
395
+ RunningTasks : make (map [int ]* TaskRunner ), // working tasks
396
+ logger : make (chan logRecord , 10000 ), // store log records to database
397
+ store : store ,
398
+ queueEvents : make (chan PoolEvent ),
399
+ aliases : make (map [string ]* TaskRunner ),
377
400
}
378
401
}
379
402
@@ -536,7 +559,6 @@ func (p *TaskPool) AddTask(
536
559
537
560
if needAlias {
538
561
taskRunner .Alias = random .String (32 )
539
- p .aliases [taskRunner .Alias ] = & taskRunner
540
562
}
541
563
542
564
err = taskRunner .populateDetails ()
0 commit comments