-
Notifications
You must be signed in to change notification settings - Fork 1
/
LibWait.groovy
78 lines (73 loc) · 3.02 KB
/
LibWait.groovy
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
import groovy.transform.CompileStatic
import groovy.util.logging.Log4j2
import javax.annotation.Nonnull
import javax.annotation.Nullable
import java.time.Duration
import java.time.Instant
import java.util.concurrent.TimeoutException
/**
* Utilities to wait for a condition to happen.
*/
@Log4j2
@CompileStatic
class LibWait {
/**
* Waits for a condition.
* @param condition Code that when evaluates to true then waiting finishes.
* @param timeout Maximum duration to wait.
* @param confidence null to stop waiting after
* condition observed for a first time,
* {@link Duration#ZERO} to sleep before
* checking for a condition again to be extra sure
* (time to sleep equals time it took for condition to turn true),
* otherwise exact time to sleep before checking again.
* @param pollPeriod How often (ms) to check for condition.
* @param description Condition description.
* @return Whatever condition returns.
* @throws TimeoutException If condition did not happen.
*/
static <T> T waitForCondition(
@Nonnull Closure<T> condition,
@Nonnull Duration timeout = Duration.ofSeconds(30),
@Nullable Duration confidence = Duration.ZERO,
@Nonnull Long pollPeriod = 500L,
@Nullable String description = null)
throws TimeoutException {
Instant startTime = Instant.now()
String conditionToUse = description ?: condition
log.info "Waiting $timeout for condition: ${conditionToUse}"
while (Instant.now().isBefore(startTime + timeout)) {
List<T> result = safely(condition,description)
if (result?.first()) {
Duration elapsed = Duration.between(startTime, Instant.now())
if (confidence == null) {
log.info "Condition ${conditionToUse} matched after $elapsed sec"
return result.first()
}
Duration confidenceTimeout = confidence == Duration.ZERO ?
elapsed :
confidence
log.info "Condition ${conditionToUse} matched after $elapsed; " +
"will be checked again after $confidenceTimeout"
Thread.sleep(confidenceTimeout.toMillis())
result = safely(condition,description)
if (result?.first()) {
log.info "Condition ${conditionToUse} again matched after $confidenceTimeout"
return result.first()
}
break
}
Thread.sleep(pollPeriod)
}
throw new TimeoutException("Failed to observe condition ${conditionToUse} within $timeout")
}
private static <T> List<T> safely(Closure<T> condition, String description) {
String conditionToUse = description ?: condition
try {
[condition()]
} catch (Exception e) {
log.info("Condition $conditionToUse has failed: " + e.message)
null
}
}
}