Context propagation mechanism for Java applications that enables carrying scoped values across API boundaries and between threads
—
Absolute time-based deadline management with automatic cancellation and timeout conversion capabilities for time-bounded operations.
Create deadlines that represent absolute points in time, generally for tracking when a task should be completed.
/**
* Create a deadline that will expire at the specified offset based on the system ticker.
* @param duration A non-negative duration
* @param units The time unit for the duration
* @return A new deadline
*/
public static Deadline after(long duration, TimeUnit units);
/**
* Create a deadline that will expire at the specified offset based on the given Ticker.
* @param duration A non-negative duration
* @param units The time unit for the duration
* @param ticker Where this deadline refers the current time
* @return A new deadline
*/
public static Deadline after(long duration, TimeUnit units, Deadline.Ticker ticker);
/**
* Returns the ticker that's based on system clock.
* @return System ticker instance
*/
public static Deadline.Ticker getSystemTicker();Usage Examples:
import java.util.concurrent.TimeUnit;
// Create a deadline 30 seconds from now
Deadline deadline = Deadline.after(30, TimeUnit.SECONDS);
// Create a deadline 5 minutes from now
Deadline longDeadline = Deadline.after(5, TimeUnit.MINUTES);
// Create deadline with custom ticker (mainly for testing)
Ticker customTicker = new CustomTicker();
Deadline testDeadline = Deadline.after(10, TimeUnit.SECONDS, customTicker);Create cancellable contexts that will automatically cancel when a deadline is reached.
/**
* Create a new context which will cancel itself after the given duration from now.
* @param duration Duration until cancellation
* @param unit Time unit for the duration
* @param scheduler Executor service for scheduling the cancellation
* @return CancellableContext that will be cancelled at the deadline
*/
public Context.CancellableContext withDeadlineAfter(long duration, TimeUnit unit, ScheduledExecutorService scheduler);
/**
* Create a new context which will cancel itself at the given Deadline.
* @param newDeadline The deadline for automatic cancellation
* @param scheduler Executor service for scheduling the cancellation
* @return CancellableContext that will be cancelled at the deadline
*/
public Context.CancellableContext withDeadline(Deadline newDeadline, ScheduledExecutorService scheduler);
/**
* Get the deadline associated with this context, if any.
* @return A Deadline or null if no deadline is set
*/
public Deadline getDeadline();Usage Examples:
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
// Create context that cancels after 5 seconds
Context.CancellableContext timedContext = Context.current()
.withDeadlineAfter(5, TimeUnit.SECONDS, scheduler);
try {
timedContext.run(() -> {
Context current = Context.current();
while (!current.isCancelled()) {
// This will automatically stop after 5 seconds
doWork();
}
});
} finally {
timedContext.cancel(null);
}
// Create context with specific deadline
Deadline deadline = Deadline.after(10, TimeUnit.MINUTES);
Context.CancellableContext deadlineContext = Context.current()
.withDeadline(deadline, scheduler);Check if a deadline has expired and get information about time remaining.
/**
* Returns whether this deadline has expired.
* @return true if expired, false otherwise
*/
public boolean isExpired();
/**
* How much time is remaining in the specified time unit.
* @param unit The time unit for the returned value
* @return Time remaining, or negative value if already expired
*/
public long timeRemaining(TimeUnit unit);Usage Examples:
Deadline deadline = Deadline.after(30, TimeUnit.SECONDS);
// Check if deadline has passed
if (deadline.isExpired()) {
System.out.println("Deadline has already expired!");
return;
}
// Get remaining time in different units
long remainingSeconds = deadline.timeRemaining(TimeUnit.SECONDS);
long remainingMillis = deadline.timeRemaining(TimeUnit.MILLISECONDS);
System.out.println("Time remaining: " + remainingSeconds + " seconds");
// Keep checking until expired
while (!deadline.isExpired()) {
doWork();
if (deadline.timeRemaining(TimeUnit.SECONDS) < 5) {
System.out.println("Warning: Less than 5 seconds remaining!");
}
}Compare deadlines to determine which expires first. Deadlines must be created with the same Ticker.
/**
* Is this deadline before another deadline.
* @param other Deadline to compare with (must use same Ticker)
* @return true if this deadline is before the other
*/
public boolean isBefore(Deadline other);
/**
* Return the minimum deadline of this or another deadline.
* @param other Deadline to compare with (must use same Ticker)
* @return The deadline that expires first
*/
public Deadline minimum(Deadline other);
/**
* Compare this deadline to another deadline.
* @param that Deadline to compare with (must use same Ticker)
* @return Negative if this is before, positive if after, zero if equal
*/
public int compareTo(Deadline that);
/**
* Check equality with another object. Two deadlines are equal if they have
* the same ticker and deadline time.
* @param object Object to compare with
* @return true if equal, false otherwise
*/
public boolean equals(Object object);
/**
* Get hash code for this deadline based on ticker and deadline time.
* @return Hash code value
*/
public int hashCode();
/**
* String representation showing time remaining until deadline.
* @return Human-readable string representation
*/
public String toString();Usage Examples:
Deadline deadline1 = Deadline.after(30, TimeUnit.SECONDS);
Deadline deadline2 = Deadline.after(60, TimeUnit.SECONDS);
// Check which deadline comes first
if (deadline1.isBefore(deadline2)) {
System.out.println("Deadline1 expires first");
}
// Get the earliest deadline
Deadline earliestDeadline = deadline1.minimum(deadline2);
// Sort deadlines (implements Comparable)
List<Deadline> deadlines = Arrays.asList(deadline2, deadline1);
Collections.sort(deadlines); // deadline1 will come firstCreate new deadlines offset from existing ones.
/**
* Create a new deadline that is offset from this deadline.
* @param offset Amount to offset (positive for later, negative for earlier)
* @param units Time unit for the offset
* @return New deadline offset from this one
*/
public Deadline offset(long offset, TimeUnit units);Usage Example:
Deadline originalDeadline = Deadline.after(60, TimeUnit.SECONDS);
// Create deadline 30 seconds later
Deadline laterDeadline = originalDeadline.offset(30, TimeUnit.SECONDS);
// Create deadline 15 seconds earlier
Deadline earlierDeadline = originalDeadline.offset(-15, TimeUnit.SECONDS);
// Original deadline is unchanged
assert originalDeadline.timeRemaining(TimeUnit.SECONDS) == 60;Schedule tasks to run when a deadline expires.
/**
* Schedule a task to be run when the deadline expires.
* @param task Task to run on expiration
* @param scheduler Executor service to schedule the task
* @return ScheduledFuture which can be used to cancel execution
*/
public ScheduledFuture<?> runOnExpiration(Runnable task, ScheduledExecutorService scheduler);Usage Example:
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
Deadline deadline = Deadline.after(30, TimeUnit.SECONDS);
// Schedule cleanup task to run when deadline expires
ScheduledFuture<?> cleanupTask = deadline.runOnExpiration(() -> {
System.out.println("Deadline expired, cleaning up resources...");
cleanupResources();
}, scheduler);
// Can cancel the scheduled task if needed
if (operationCompleted) {
cleanupTask.cancel(false);
}Create custom time sources for testing or specialized timing needs.
/**
* Time source representing nanoseconds since fixed but arbitrary point in time.
* DO NOT use custom Ticker implementations in production.
*/
public abstract static class Ticker {
/**
* Returns the number of nanoseconds elapsed since this ticker's reference point in time.
* @return Nanoseconds elapsed
*/
public abstract long nanoTime();
}Usage Example (Testing Only):
// Custom ticker for testing - DO NOT USE IN PRODUCTION
public class TestTicker extends Deadline.Ticker {
private long currentTime = 0;
@Override
public long nanoTime() {
return currentTime;
}
public void advance(long nanos) {
currentTime += nanos;
}
}
// Use in tests only
TestTicker testTicker = new TestTicker();
Deadline testDeadline = Deadline.after(1000, TimeUnit.MILLISECONDS, testTicker);
assert !testDeadline.isExpired();
testTicker.advance(TimeUnit.SECONDS.toNanos(2)); // Advance 2 seconds
assert testDeadline.isExpired();Install with Tessl CLI
npx tessl i tessl/maven-io-grpc--grpc-context