github.com/git-amp/amp-sdk-go@v0.7.5/stdlib/task/pool_worker.go (about)

     1  package task
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"time"
     7  )
     8  
     9  type PoolWorker interface {
    10  	Context
    11  	Add(item PoolWorkerItem)
    12  	ForceRetry(uniqueID PoolUniqueID)
    13  }
    14  
    15  type PoolWorkerItem interface {
    16  	PoolUniqueIDer
    17  	Work(ctx context.Context) (retry bool)
    18  }
    19  
    20  type PoolWorkerScheduler interface {
    21  	CheckForRetriesInterval() time.Duration
    22  	RetryWhen(item PoolWorkerItem) time.Time
    23  }
    24  
    25  type poolWorker struct {
    26  	Context
    27  	name        string
    28  	concurrency int
    29  	pool        *Pool
    30  	scheduler   PoolWorkerScheduler
    31  }
    32  
    33  func StartNewPoolWorker(name string, concurrency int, scheduler PoolWorkerScheduler) (*poolWorker, error) {
    34  	w := &poolWorker{
    35  		name:        name,
    36  		concurrency: concurrency,
    37  		scheduler:   scheduler,
    38  	}
    39  	
    40  	w.pool = StartNewPool(name, concurrency, scheduler.CheckForRetriesInterval())
    41  	var err error
    42  	w.Context, err = Start(&Task{
    43  		Label: "tester",
    44  		OnStart: w.OnContextStarted,
    45  	})
    46  	return w, err
    47  }
    48  
    49  func (w *poolWorker) OnContextStarted(ctx Context) error {
    50  	_, err := w.StartChild(&Task{
    51  		Label: "poolWorker",
    52  		OnStart: w.pool.OnContextStarted,
    53  	})
    54  	if err != nil {
    55  		return err
    56  	}
    57  
    58  	for i := 0; i < w.concurrency; i++ {
    59  		w.Context.Go(fmt.Sprintf("worker %v", i), func(ctx Context) {
    60  			for {
    61  				select {
    62  				case <-ctx.Done():
    63  					return
    64  				default:
    65  				}
    66  
    67  				x, err := w.pool.Get(ctx)
    68  				if err != nil {
    69  					return
    70  				}
    71  				item := x.(PoolWorkerItem)
    72  
    73  				retry := item.Work(ctx)
    74  				if retry {
    75  					w.pool.RetryLater(item.ID(), w.scheduler.RetryWhen(item))
    76  				} else {
    77  					w.pool.Complete(item.ID())
    78  				}
    79  			}
    80  		})
    81  	}
    82  	return nil
    83  }
    84  
    85  func (w *poolWorker) Add(item PoolWorkerItem) {
    86  	w.pool.Add(item)
    87  }
    88  
    89  func (w *poolWorker) ForceRetry(id PoolUniqueID) {
    90  	w.pool.ForceRetry(id)
    91  }
    92  
    93  type StaticScheduler struct {
    94  	checkForRetriesInterval time.Duration
    95  	retryAfter              time.Duration
    96  }
    97  
    98  var _ PoolWorkerScheduler = StaticScheduler{}
    99  
   100  func NewStaticScheduler(checkForRetriesInterval time.Duration, retryAfter time.Duration) StaticScheduler {
   101  	return StaticScheduler{checkForRetriesInterval, retryAfter}
   102  }
   103  
   104  func (s StaticScheduler) CheckForRetriesInterval() time.Duration { return s.checkForRetriesInterval }
   105  func (s StaticScheduler) RetryWhen(item PoolWorkerItem) time.Time {
   106  	return time.Now().Add(s.retryAfter)
   107  }