github.com/jacobsoderblom/buffalo@v0.11.0/worker/simple.go (about)

     1  package worker
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  	"time"
     7  
     8  	"github.com/pkg/errors"
     9  	"github.com/sirupsen/logrus"
    10  )
    11  
    12  var _ Worker = &Simple{}
    13  
    14  // NewSimple creates a basic implementation of the Worker interface
    15  // that is backed using just the standard library and goroutines.
    16  func NewSimple() *Simple {
    17  	return NewSimpleWithContext(context.Background())
    18  }
    19  
    20  // NewSimpleWithContext creates a basic implementation of the Worker interface
    21  // that is backed using just the standard library and goroutines.
    22  func NewSimpleWithContext(ctx context.Context) *Simple {
    23  	ctx, cancel := context.WithCancel(ctx)
    24  
    25  	l := logrus.New()
    26  	l.Level = logrus.InfoLevel
    27  	l.Formatter = &logrus.TextFormatter{}
    28  
    29  	return &Simple{
    30  		Logger:   l,
    31  		ctx:      ctx,
    32  		cancel:   cancel,
    33  		handlers: map[string]Handler{},
    34  		moot:     &sync.Mutex{},
    35  	}
    36  }
    37  
    38  // Simple is a basic implementation of the Worker interface
    39  // that is backed using just the standard library and goroutines.
    40  type Simple struct {
    41  	Logger   SimpleLogger
    42  	ctx      context.Context
    43  	cancel   context.CancelFunc
    44  	handlers map[string]Handler
    45  	moot     *sync.Mutex
    46  }
    47  
    48  // Register Handler with the worker
    49  func (w *Simple) Register(name string, h Handler) error {
    50  	w.moot.Lock()
    51  	defer w.moot.Unlock()
    52  	if _, ok := w.handlers[name]; ok {
    53  		return errors.Errorf("handler already mapped for name %s", name)
    54  	}
    55  	w.handlers[name] = h
    56  	return nil
    57  }
    58  
    59  // Start the worker
    60  func (w *Simple) Start(ctx context.Context) error {
    61  	w.Logger.Info("Starting Simple Background Worker")
    62  	w.ctx, w.cancel = context.WithCancel(ctx)
    63  	return nil
    64  }
    65  
    66  // Stop the worker
    67  func (w Simple) Stop() error {
    68  	w.Logger.Info("Stopping Simple Background Worker")
    69  	w.cancel()
    70  	return nil
    71  }
    72  
    73  // Perform a job as soon as possibly using a goroutine.
    74  func (w Simple) Perform(job Job) error {
    75  	w.Logger.Debugf("Performing job %s", job)
    76  	if job.Handler == "" {
    77  		err := errors.Errorf("no handler name given for %s", job)
    78  		w.Logger.Error(err)
    79  		return err
    80  	}
    81  	w.moot.Lock()
    82  	defer w.moot.Unlock()
    83  	if h, ok := w.handlers[job.Handler]; ok {
    84  		go func() {
    85  			err := h(job.Args)
    86  			if err != nil {
    87  				w.Logger.Error(err)
    88  			}
    89  			w.Logger.Debugf("Completed job %s", job)
    90  		}()
    91  		return nil
    92  	}
    93  	err := errors.Errorf("no handler mapped for name %s", job.Handler)
    94  	w.Logger.Error(err)
    95  	return err
    96  }
    97  
    98  // PerformAt performs a job at a particular time using a goroutine.
    99  func (w Simple) PerformAt(job Job, t time.Time) error {
   100  	return w.PerformIn(job, time.Until(t))
   101  }
   102  
   103  // PerformIn performs a job after waiting for a specified amount
   104  // using a goroutine.
   105  func (w Simple) PerformIn(job Job, d time.Duration) error {
   106  	go func() {
   107  		select {
   108  		case <-time.After(d):
   109  			w.Perform(job)
   110  		case <-w.ctx.Done():
   111  			w.cancel()
   112  		}
   113  	}()
   114  	return nil
   115  }
   116  
   117  // SimpleLogger is used by the Simple worker to write logs
   118  type SimpleLogger interface {
   119  	Debugf(string, ...interface{})
   120  	Infof(string, ...interface{})
   121  	Errorf(string, ...interface{})
   122  	Debug(...interface{})
   123  	Info(...interface{})
   124  	Error(...interface{})
   125  }