File: wait.go

package info (click to toggle)
golang-github-scaleway-scaleway-sdk-go 1.0.0~beta12-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 3,000 kB
  • sloc: javascript: 160; sh: 70; makefile: 3
file content (90 lines) | stat: -rw-r--r-- 2,088 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package async

import (
	"fmt"
	"time"
)

var (
	defaultInterval = time.Second
	defaultTimeout  = time.Minute * 5
)

type IntervalStrategy func() <-chan time.Time

// WaitSyncConfig defines the waiting options.
type WaitSyncConfig struct {
	// This method will be called from another goroutine.
	Get              func() (value interface{}, isTerminal bool, err error)
	IntervalStrategy IntervalStrategy
	Timeout          time.Duration
}

// LinearIntervalStrategy defines a linear interval duration.
func LinearIntervalStrategy(interval time.Duration) IntervalStrategy {
	return func() <-chan time.Time {
		return time.After(interval)
	}
}

// FibonacciIntervalStrategy defines an interval duration who follow the Fibonacci sequence.
func FibonacciIntervalStrategy(base time.Duration, factor float32) IntervalStrategy {
	var x, y float32 = 0, 1

	return func() <-chan time.Time {
		x, y = y, x+(y*factor)
		return time.After(time.Duration(x) * base)
	}
}

// WaitSync waits and returns when a given stop condition is true or if an error occurs.
func WaitSync(config *WaitSyncConfig) (terminalValue interface{}, err error) {
	// initialize configuration
	if config.IntervalStrategy == nil {
		config.IntervalStrategy = LinearIntervalStrategy(defaultInterval)
	}

	if config.Timeout == 0 {
		config.Timeout = defaultTimeout
	}

	resultValue := make(chan interface{})
	resultErr := make(chan error)
	timeout := make(chan bool)

	go func() {
		for {
			// get the payload
			value, stopCondition, err := config.Get()

			// send the payload
			if err != nil {
				resultErr <- err
				return
			}
			if stopCondition {
				resultValue <- value
				return
			}

			// waiting for an interval before next get() call or a timeout
			select {
			case <-timeout:
				return
			case <-config.IntervalStrategy():
				// sleep
			}
		}
	}()

	// waiting for a result or a timeout
	select {
	case val := <-resultValue:
		return val, nil
	case err := <-resultErr:
		return nil, err
	case <-time.After(config.Timeout):
		timeout <- true
		return nil, fmt.Errorf("timeout after %v", config.Timeout)
	}
}