4
4
"context"
5
5
"encoding/json"
6
6
"fmt"
7
+ "math"
7
8
"runtime/debug"
8
9
"sync"
9
10
"time"
24
25
ErrValidation = errors .New ("validation error" )
25
26
ErrAlreadyScheduled = errors .New ("already scheduled" )
26
27
ErrUnableToResolve = errors .New ("unable to resolve task" )
28
+
29
+ initialInterval = 500 * time .Millisecond
30
+ backoffCoefficient = 2.0
31
+ maximumInterval = 120 * time .Second
27
32
)
28
33
29
34
type Scheduler interface {
@@ -455,7 +460,6 @@ func (s *DefaultTaskScheduler) startTask(ctx context.Context, descriptor models.
455
460
ctx ,
456
461
logger ,
457
462
holder ,
458
- descriptor ,
459
463
options ,
460
464
taskResolver ,
461
465
container ,
@@ -568,6 +572,7 @@ func (s *DefaultTaskScheduler) runTaskOnce(
568
572
return err
569
573
}
570
574
575
+ retries := 0
571
576
loop:
572
577
for {
573
578
select {
@@ -581,7 +586,22 @@ loop:
581
586
case err == nil :
582
587
break loop
583
588
case errors .Is (err , ErrRetryable ):
584
- logger .Infof ("Task terminated with retryable error: %s" , err )
589
+ retries ++
590
+ backoffInterval := time .Duration (float64 (initialInterval ) * math .Pow (backoffCoefficient , float64 (retries - 1 )))
591
+ if backoffInterval > maximumInterval {
592
+ backoffInterval = maximumInterval
593
+ }
594
+
595
+ timer := time .NewTimer (backoffInterval )
596
+ logger .Infof ("Task terminated with retryable error: %s, retrying in %s" , err , backoffInterval )
597
+ select {
598
+ case <- ctx .Done ():
599
+ timer .Stop ()
600
+ return
601
+ case <- timer .C :
602
+ timer .Stop ()
603
+ }
604
+
585
605
continue
586
606
case errors .Is (err , ErrNonRetryable ):
587
607
logger .Infof ("Task terminated with non retryable error: %s" , err )
@@ -621,7 +641,6 @@ func (s *DefaultTaskScheduler) runTaskPeriodically(
621
641
ctx context.Context ,
622
642
logger logging.Logger ,
623
643
holder * taskHolder ,
624
- descriptor models.TaskDescriptor ,
625
644
options models.TaskSchedulerOptions ,
626
645
taskResolver Task ,
627
646
container * dig.Container ,
@@ -679,12 +698,34 @@ func (s *DefaultTaskScheduler) runTaskPeriodically(
679
698
680
699
logger .Infof ("Starting task..." )
681
700
ticker := time .NewTicker (options .Duration )
701
+ retries := 0
682
702
for {
683
703
stopped , err := processFunc ()
684
704
switch {
685
705
case err == nil :
686
706
// Doing nothing, waiting for the next tick
687
707
case errors .Is (err , ErrRetryable ):
708
+ retries ++
709
+ backoffInterval := time .Duration (float64 (initialInterval ) * math .Pow (backoffCoefficient , float64 (retries - 1 )))
710
+ if backoffInterval > maximumInterval {
711
+ backoffInterval = maximumInterval
712
+ }
713
+
714
+ timer := time .NewTimer (backoffInterval )
715
+ logger .Infof ("Task terminated with retryable error: %s, retrying in %s" , err , backoffInterval )
716
+ select {
717
+ case <- ctx .Done ():
718
+ timer .Stop ()
719
+ return
720
+ case ch := <- holder .stopChan :
721
+ logger .Infof ("Stopping task..." )
722
+ close (ch )
723
+ timer .Stop ()
724
+ return
725
+ case <- timer .C :
726
+ timer .Stop ()
727
+ }
728
+
688
729
ticker .Reset (options .Duration )
689
730
continue
690
731
case errors .Is (err , ErrNonRetryable ):
0 commit comments