github.com/Jeffail/benthos/v3@v3.65.0/lib/processor/sleep.go (about)

     1  package processor
     2  
     3  import (
     4  	"fmt"
     5  	"sync/atomic"
     6  	"time"
     7  
     8  	"github.com/Jeffail/benthos/v3/internal/bloblang/field"
     9  	"github.com/Jeffail/benthos/v3/internal/docs"
    10  	"github.com/Jeffail/benthos/v3/internal/interop"
    11  	"github.com/Jeffail/benthos/v3/internal/tracing"
    12  	"github.com/Jeffail/benthos/v3/lib/log"
    13  	"github.com/Jeffail/benthos/v3/lib/metrics"
    14  	"github.com/Jeffail/benthos/v3/lib/types"
    15  )
    16  
    17  //------------------------------------------------------------------------------
    18  
    19  func init() {
    20  	Constructors[TypeSleep] = TypeSpec{
    21  		constructor: NewSleep,
    22  		Categories: []Category{
    23  			CategoryUtility,
    24  		},
    25  		Summary: `
    26  Sleep for a period of time specified as a duration string. This processor will
    27  interpolate functions within the ` + "`duration`" + ` field, you can find a list
    28  of functions [here](/docs/configuration/interpolation#bloblang-queries).`,
    29  		Description: `
    30  This processor executes once per message batch. In order to execute once for
    31  each message of a batch place it within a
    32  ` + "[`for_each`](/docs/components/processors/for_each)" + ` processor:
    33  
    34  ` + "```yaml" + `
    35  pipeline:
    36    processors:
    37      - for_each:
    38        - sleep:
    39            duration: ${! meta("sleep_for") }
    40  ` + "```" + ``,
    41  		FieldSpecs: docs.FieldSpecs{
    42  			docs.FieldInterpolatedString("duration", "The duration of time to sleep for each execution."),
    43  		},
    44  	}
    45  }
    46  
    47  //------------------------------------------------------------------------------
    48  
    49  // SleepConfig contains configuration fields for the Sleep processor.
    50  type SleepConfig struct {
    51  	Duration string `json:"duration" yaml:"duration"`
    52  }
    53  
    54  // NewSleepConfig returns a SleepConfig with default values.
    55  func NewSleepConfig() SleepConfig {
    56  	return SleepConfig{
    57  		Duration: "100us",
    58  	}
    59  }
    60  
    61  //------------------------------------------------------------------------------
    62  
    63  // Sleep is a processor that limits the stream of a pipeline to one message
    64  // batch per period specified.
    65  type Sleep struct {
    66  	closed    int32
    67  	closeChan chan struct{}
    68  
    69  	conf  Config
    70  	log   log.Modular
    71  	stats metrics.Type
    72  
    73  	durationStr *field.Expression
    74  
    75  	mCount     metrics.StatCounter
    76  	mErr       metrics.StatCounter
    77  	mSent      metrics.StatCounter
    78  	mBatchSent metrics.StatCounter
    79  }
    80  
    81  // NewSleep returns a Sleep processor.
    82  func NewSleep(
    83  	conf Config, mgr types.Manager, log log.Modular, stats metrics.Type,
    84  ) (Type, error) {
    85  	durationStr, err := interop.NewBloblangField(mgr, conf.Sleep.Duration)
    86  	if err != nil {
    87  		return nil, fmt.Errorf("failed to parse duration expression: %v", err)
    88  	}
    89  	t := &Sleep{
    90  		closeChan: make(chan struct{}),
    91  		conf:      conf,
    92  		log:       log,
    93  		stats:     stats,
    94  
    95  		durationStr: durationStr,
    96  
    97  		mCount:     stats.GetCounter("count"),
    98  		mErr:       stats.GetCounter("error"),
    99  		mSent:      stats.GetCounter("sent"),
   100  		mBatchSent: stats.GetCounter("batch.sent"),
   101  	}
   102  	return t, nil
   103  }
   104  
   105  //------------------------------------------------------------------------------
   106  
   107  // ProcessMessage applies the processor to a message, either creating >0
   108  // resulting messages or a response to be sent back to the message source.
   109  func (s *Sleep) ProcessMessage(msg types.Message) ([]types.Message, types.Response) {
   110  	s.mCount.Incr(1)
   111  
   112  	spans := tracing.CreateChildSpans(TypeSleep, msg)
   113  	defer func() {
   114  		for _, span := range spans {
   115  			span.Finish()
   116  		}
   117  	}()
   118  
   119  	period, err := time.ParseDuration(s.durationStr.String(0, msg))
   120  	if err != nil {
   121  		s.log.Errorf("Failed to parse duration: %v\n", err)
   122  		s.mErr.Incr(1)
   123  	}
   124  	select {
   125  	case <-time.After(period):
   126  	case <-s.closeChan:
   127  	}
   128  
   129  	s.mBatchSent.Incr(1)
   130  	s.mSent.Incr(int64(msg.Len()))
   131  	msgs := [1]types.Message{msg}
   132  	return msgs[:], nil
   133  }
   134  
   135  // CloseAsync shuts down the processor and stops processing requests.
   136  func (s *Sleep) CloseAsync() {
   137  	if atomic.CompareAndSwapInt32(&s.closed, 0, 1) {
   138  		close(s.closeChan)
   139  	}
   140  }
   141  
   142  // WaitForClose blocks until the processor has closed down.
   143  func (s *Sleep) WaitForClose(timeout time.Duration) error {
   144  	return nil
   145  }
   146  
   147  //------------------------------------------------------------------------------