com.yahoo.vespa.config.server.TimeoutBudget Maven / Gradle / Ivy
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server;
import com.yahoo.concurrent.UncheckedTimeoutException;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
/**
* Handles a timeout logic by providing higher level abstraction for asking if there is time left.
*
* @author Ulf Lilleengen
*/
public class TimeoutBudget {
private final Clock clock;
private final Instant startTime;
private final List measurements = new ArrayList<>();
private final Instant endTime;
public TimeoutBudget(Clock clock, Duration duration) {
this.clock = clock;
this.startTime = clock.instant();
this.endTime = startTime.plus(duration);
}
public Duration timeout() {
return Duration.between(startTime, endTime);
}
public Duration timeLeft() {
Instant now = clock.instant();
Duration duration = Duration.between(now, endTime);
return duration.isNegative() ? Duration.ZERO : duration;
}
public boolean hasTimeLeft() {
return clock.instant().isBefore(endTime);
}
public boolean hasTimeLeft(String step) {
Instant now = clock.instant();
measurements.add(new Measurement(now, step));
return now.isBefore(endTime);
}
public String timesUsed() {
StringBuilder buf = new StringBuilder();
buf.append("[");
Instant prev = startTime;
for (Measurement m : measurements) {
if ( ! m.label().isEmpty()) {
buf.append(m.label()).append(": ");
}
buf.append(Duration.between(prev, m.timestamp()).toMillis())
.append(" ms")
.append(", ");
prev = m.timestamp();
}
Instant now = clock.instant();
buf.append("total: ");
buf.append(Duration.between(startTime, now).toMillis());
buf.append(" ms]");
return buf.toString();
}
/**
* @param exceptionMessage exception message for the exception that will be thrown if there is no time left
* @throws UncheckedTimeoutException if this has no time left
*/
public void assertNotTimedOut(Supplier exceptionMessage) {
if (hasTimeLeft()) return;
throw new UncheckedTimeoutException(exceptionMessage.get());
}
private static class Measurement {
private final Instant timestamp;
private final String label;
Measurement(Instant timestamp, String label) {
this.timestamp = timestamp;
this.label = label;
}
public Instant timestamp() {
return timestamp;
}
public String label() {
return label;
}
}
}