Timers
The time module provides duration/instant types and three async timer primitives: Sleep, Deadline, and Interval.
Duration and Instant
Section titled “Duration and Instant”Duration
Section titled “Duration”A Duration represents a span of time with nanosecond precision. All arithmetic saturates instead of overflowing.
const volt = @import("volt");const Duration = volt.time.Duration;
// Creationconst d1 = Duration.fromNanos(500);const d2 = Duration.fromMicros(100);const d3 = Duration.fromMillis(250);const d4 = Duration.fromSecs(5);const d5 = Duration.fromMins(2);const d6 = Duration.fromHours(1);const d7 = Duration.fromDays(7);
// Conversiond4.asNanos(); // 5_000_000_000d4.asMicros(); // 5_000_000d4.asMillis(); // 5_000d4.asSecs(); // 5
// Arithmetic (saturating)const sum = d3.add(d4); // 5.25 secondsconst diff = d4.sub(d3); // 4.75 secondsconst scaled = d3.mul(4); // 1 secondconst halved = d4.div(2); // 2.5 seconds
// Comparisonconst order = d3.cmp(d4); // .ltconst is_zero = Duration.ZERO.isZero(); // true
// Constants_ = Duration.ZERO; // 0ns_ = Duration.MAX; // u64 max nanoseconds
// Readable aliasesconst timeout = Duration.fromSeconds(30);const period = Duration.fromMinutes(5);Instant
Section titled “Instant”An Instant represents a point on the monotonic clock, suitable for measuring elapsed time:
const Instant = volt.time.Instant;
const start = Instant.now();
// ... do work ...
const elapsed = start.elapsed(); // Durationstd.debug.print("Took {d}ms\n", .{elapsed.asMillis()});
// Comparisonsconst a = Instant.now();const b = a.add(Duration.fromSecs(1));a.isBefore(b); // trueb.isAfter(a); // true
// Difference between instantsconst diff = b.durationSince(a); // ~1 secondSleep suspends execution for a specified duration. It uses the waiter pattern consistent with all other Volt primitives.
Creation
Section titled “Creation”const time = volt.time;
// Sleep for a durationvar sleep = time.Sleep.init(Duration.fromMillis(100));
// Sleep until a specific instantvar sleep2 = time.Sleep.initUntil(Instant.now().add(Duration.fromSecs(5)));Convenience constructors
Section titled “Convenience constructors”var sleep = time.sleep(Duration.fromMillis(500));var sleep2 = time.sleepUntil(deadline_instant);Waiter API
Section titled “Waiter API”var waiter = time.SleepWaiter.init();waiter.setWaker(@ptrCast(&my_ctx), myWakeCallback);
if (!sleep.wait(&waiter)) { // Sleep has not elapsed yet. Yield to scheduler. // Waiter will be woken when the deadline passes.}// waiter.isComplete() is true -- sleep is done.Polling (non-blocking check)
Section titled “Polling (non-blocking check)”if (sleep.tryWait()) { // Duration has elapsed} else { // Still waiting}Cancellation
Section titled “Cancellation”sleep.cancelWait(&waiter);Blocking sleep
Section titled “Blocking sleep”For non-async contexts (tests, initialization code):
time.blockingSleep(Duration.fromMillis(100));This calls std.Thread.sleep under the hood and blocks the current OS thread.
Deadline / Timeout
Section titled “Deadline / Timeout”A Deadline tracks a point in time after which an operation should abort. Use it to implement timeouts on any async operation.
Creation
Section titled “Creation”const time = volt.time;
// Expire 5 seconds from nowvar deadline = time.Deadline.init(Duration.fromSecs(5));
// Or use the convenience functionvar deadline2 = time.deadline(Duration.fromSecs(5));Checking expiration
Section titled “Checking expiration”if (deadline.isExpired()) { return error.TimedOut;}
// Remaining timeconst remaining = deadline.remaining(); // Duration (zero if expired)Waiter API
Section titled “Waiter API”var waiter = time.DeadlineWaiter.init();waiter.setWaker(@ptrCast(&my_ctx), myWakeCallback);
if (!deadline.wait(&waiter)) { // Deadline has not expired yet. Yield to scheduler. // Woken when deadline expires.}// waiter.isComplete() is true -- deadline has passed.Timeout pattern
Section titled “Timeout pattern”Use a Deadline with an async task to implement timeouts on any operation:
// Set a 5 second deadlinevar deadline = time.Deadline.init(Duration.fromSecs(5));
// Spawn the async operationvar read_f = try io.@"async"(readFromStream, .{stream, &buf});
// Check if the deadline has expired before awaitingif (deadline.isExpired()) { return error.TimedOut;}
const result = read_f.@"await"(io);handleResult(result);Pattern: operation with retry and timeout
Section titled “Pattern: operation with retry and timeout”fn fetchWithTimeout(url: []const u8) !Response { var deadline = volt.time.Deadline.init(Duration.fromSecs(30));
var attempts: usize = 0; while (attempts < 3) : (attempts += 1) { if (deadline.isExpired()) { return error.TimedOut; }
const result = tryFetch(url) catch |err| { if (err == error.ConnectionRefused) { // Wait before retry, but respect the overall deadline const backoff = Duration.fromMillis(100).mul(attempts + 1); const remaining = deadline.remaining(); const wait_time = if (backoff.asNanos() < remaining.asNanos()) backoff else remaining; volt.time.blockingSleep(wait_time); continue; } return err; };
return result; }
return error.MaxRetriesExceeded;}Interval
Section titled “Interval”An Interval fires repeatedly at a fixed period. It compensates for drift so that ticks stay aligned to the original schedule.
Creation
Section titled “Creation”const time = volt.time;
// Tick every 100msvar interval = time.Interval.init(Duration.fromMillis(100));
// Or use the convenience functionvar interval2 = time.interval(Duration.fromSecs(1));Tick loop
Section titled “Tick loop”while (running) { var waiter = time.IntervalWaiter.init(); waiter.setWaker(@ptrCast(&my_ctx), myWakeCallback);
if (!interval.tick(&waiter)) { // Next tick has not arrived. Yield to scheduler. } // Tick fired -- do periodic work collectMetrics(); reportHealth();}Non-blocking tick
Section titled “Non-blocking tick”if (interval.tryTick()) { // A tick period has elapsed since the last tick doPeriodicWork();}Missed tick behavior
Section titled “Missed tick behavior”When processing takes longer than the interval period, the MissedTickBehavior controls what happens:
| Behavior | Description |
|---|---|
burst | Fire immediately for each missed tick (catch up) |
skip | Skip missed ticks and schedule from now |
delay | Delay the next tick from now (default) |
var interval = time.Interval.init(Duration.fromMillis(100));interval.missed_tick_behavior = .skip; // Skip missed ticksPattern: periodic health check
Section titled “Pattern: periodic health check”fn healthCheckLoop() void { var interval = volt.time.Interval.init(Duration.fromSecs(30));
while (running) { var waiter = volt.time.IntervalWaiter.init(); if (!interval.tick(&waiter)) { // Yield to scheduler }
const health = checkSystemHealth(); if (!health.ok) { alertOps(health); } reportMetrics(health); }}Timer driver integration
Section titled “Timer driver integration”The timer primitives can integrate with the runtime’s TimerDriver for event-loop-driven wakeups instead of polling. The timer driver uses a hierarchical timer wheel (similar to Tokio’s) for efficient scheduling of thousands of concurrent timers.
const driver = volt.time.getDriver();if (driver) |d| { var entry: volt.time.TimerHandle = undefined; try d.register(&entry, deadline, &waiter); // Timer will fire automatically through the event loop}In most cases you do not need to interact with the timer driver directly — the Sleep, Deadline, and Interval types handle registration automatically when running inside the Volt runtime.