github.com/uber/kraken@v0.1.4/utils/dedup/interval_trap.go (about)

     1  // Copyright (c) 2016-2019 Uber Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  package dedup
    15  
    16  import (
    17  	"sync"
    18  	"time"
    19  
    20  	"github.com/andres-erbsen/clock"
    21  )
    22  
    23  // IntervalTask defines a task to run on some interval.
    24  type IntervalTask interface {
    25  	Run()
    26  }
    27  
    28  // IntervalTrap manages trapping into some task which must run at a given interval.
    29  type IntervalTrap struct {
    30  	sync.RWMutex
    31  	clk      clock.Clock
    32  	interval time.Duration
    33  	prev     time.Time
    34  	task     IntervalTask
    35  }
    36  
    37  // NewIntervalTrap creates a new IntervalTrap.
    38  func NewIntervalTrap(
    39  	interval time.Duration, clk clock.Clock, task IntervalTask) *IntervalTrap {
    40  
    41  	return &IntervalTrap{
    42  		clk:      clk,
    43  		interval: interval,
    44  		prev:     clk.Now(),
    45  		task:     task,
    46  	}
    47  }
    48  
    49  func (t *IntervalTrap) ready() bool {
    50  	return t.clk.Now().After(t.prev.Add(t.interval))
    51  }
    52  
    53  // Trap quickly checks if the interval has passed since the last task run, and if
    54  // it has, it runs the task.
    55  func (t *IntervalTrap) Trap() {
    56  	t.RLock()
    57  	ready := t.ready()
    58  	t.RUnlock()
    59  	if !ready {
    60  		return
    61  	}
    62  
    63  	t.Lock()
    64  	defer t.Unlock()
    65  	if !t.ready() {
    66  		return
    67  	}
    68  	t.task.Run()
    69  	t.prev = t.clk.Now()
    70  }