github.com/imannamdari/v2ray-core/v5@v5.0.5/common/task/periodic.go (about)

     1  package task
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  )
     7  
     8  // Periodic is a task that runs periodically.
     9  type Periodic struct {
    10  	// Interval of the task being run
    11  	Interval time.Duration
    12  	// Execute is the task function
    13  	Execute func() error
    14  
    15  	access  sync.Mutex
    16  	timer   *time.Timer
    17  	running bool
    18  }
    19  
    20  func (t *Periodic) hasClosed() bool {
    21  	t.access.Lock()
    22  	defer t.access.Unlock()
    23  
    24  	return !t.running
    25  }
    26  
    27  func (t *Periodic) checkedExecute() error {
    28  	if t.hasClosed() {
    29  		return nil
    30  	}
    31  
    32  	if err := t.Execute(); err != nil {
    33  		t.access.Lock()
    34  		t.running = false
    35  		t.access.Unlock()
    36  		return err
    37  	}
    38  
    39  	t.access.Lock()
    40  	defer t.access.Unlock()
    41  
    42  	if !t.running {
    43  		return nil
    44  	}
    45  
    46  	t.timer = time.AfterFunc(t.Interval, func() {
    47  		t.checkedExecute()
    48  	})
    49  
    50  	return nil
    51  }
    52  
    53  // Start implements common.Runnable.
    54  func (t *Periodic) Start() error {
    55  	t.access.Lock()
    56  	if t.running {
    57  		t.access.Unlock()
    58  		return nil
    59  	}
    60  	t.running = true
    61  	t.access.Unlock()
    62  
    63  	if err := t.checkedExecute(); err != nil {
    64  		t.access.Lock()
    65  		t.running = false
    66  		t.access.Unlock()
    67  		return err
    68  	}
    69  
    70  	return nil
    71  }
    72  
    73  // Close implements common.Closable.
    74  func (t *Periodic) Close() error {
    75  	t.access.Lock()
    76  	defer t.access.Unlock()
    77  
    78  	t.running = false
    79  	if t.timer != nil {
    80  		t.timer.Stop()
    81  		t.timer = nil
    82  	}
    83  
    84  	return nil
    85  }