or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

concurrency.mdcore-io.mdindex.mdresources.mdruntime.mdstd.mdtime.md
tile.json

time.mddocs/

Time and Scheduling

Time-based operations including delays, timeouts, scheduling, and timing measurements. Cats Effect provides comprehensive temporal operations that integrate with the cancellation and concurrency system.

Capabilities

Sleep and Delays

Basic time-based pausing and delay operations.

/**
 * Sleep for specified duration
 * @param duration - How long to sleep
 * @returns IO[Unit] that completes after the duration
 */
def IO.sleep(duration: FiniteDuration): IO[Unit]

/**
 * Add delay before executing IO
 * @param duration - Delay duration
 * @returns IO[A] that executes after delay
 */
def delayBy(duration: FiniteDuration): IO[A]

/**
 * Add delay after executing IO
 * @param duration - Delay duration
 * @returns IO[A] that delays after completion
 */
def andWait(duration: FiniteDuration): IO[A]

Timeouts

Apply time limits to IO operations with various fallback strategies.

/**
 * Apply timeout to IO operation
 * @param duration - Maximum time allowed
 * @returns IO[A] that fails with TimeoutException if exceeded
 */
def timeout(duration: FiniteDuration): IO[A]

/**
 * Apply timeout with fallback value
 * @param duration - Maximum time allowed
 * @param fallback - IO to run if timeout occurs
 * @returns IO[AA] using fallback on timeout
 */
def timeoutTo[AA >: A](duration: FiniteDuration, fallback: IO[AA]): IO[AA]

/**
 * Apply timeout without cancellation
 * @param duration - Maximum time allowed
 * @returns IO[A] that continues running but returns None on timeout
 */
def timeoutAndForget(duration: FiniteDuration): IO[Option[A]]

Timing and Measurement

Measure execution time and add timing information.

/**
 * Measure execution time of IO
 * @returns IO[(FiniteDuration, A)] with duration and result
 */
def timed: IO[(FiniteDuration, A)]

/**
 * Get current monotonic time (for measuring intervals)
 * @returns IO[FiniteDuration] with monotonic time
 */
def IO.monotonic: IO[FiniteDuration]

/**
 * Get current real time (wall clock time)
 * @returns IO[FiniteDuration] with real time since epoch
 */
def IO.realTime: IO[FiniteDuration]

/**
 * Get current time in milliseconds
 * @returns IO[Long] with current time millis
 */
def Clock[IO].realTime: IO[FiniteDuration]

/**
 * Get monotonic time in nanoseconds
 * @returns IO[Long] with monotonic nanos
 */
def Clock[IO].monotonic: IO[FiniteDuration]

Scheduled Execution

Control timing of repeated and scheduled operations.

/**
 * Repeat IO with fixed delay between executions
 * @param delay - Delay between executions
 * @returns IO that repeats with delay
 */
def IO.sleep(delay: FiniteDuration).foreverM: IO[Nothing]

/**
 * Run IO at fixed intervals (approximate)
 * @param interval - Target interval between starts
 * @param fa - IO to run repeatedly
 * @returns IO[Nothing] that runs forever at intervals
 */
def fixedRate[A](interval: FiniteDuration)(fa: IO[A]): IO[Nothing]

/**
 * Run IO with fixed delay between completions
 * @param delay - Delay between completion and next start
 * @param fa - IO to run repeatedly  
 * @returns IO[Nothing] that runs with fixed delays
 */
def fixedDelay[A](delay: FiniteDuration)(fa: IO[A]): IO[Nothing]

Temporal Combinators

Advanced temporal coordination between multiple operations.

/**
 * Race IO against a timeout
 * @param duration - Timeout duration
 * @returns IO[Either[Unit, A]] - Left(()) for timeout, Right(a) for success
 */
def raceTimeout(duration: FiniteDuration): IO[Either[Unit, A]]

/**
 * Apply maximum execution time (similar to timeout but different semantics)
 * @param duration - Maximum duration
 * @returns IO[A] that fails if duration exceeded
 */
def within(duration: FiniteDuration): IO[A]

/**
 * Ensure minimum execution time
 * @param duration - Minimum duration
 * @returns IO[A] that waits if completing too quickly
 */
def guaranteeMinimum(duration: FiniteDuration): IO[A]

Clock Operations

Lower-level clock operations for custom timing logic.

/**
 * Get Clock instance for IO
 * @returns Clock[IO] for time operations
 */
implicit def Clock[IO]: Clock[IO]

/**
 * Measure elapsed time for a computation
 * @param fa - IO to measure
 * @returns IO[(FiniteDuration, A)] with elapsed time
 */
def Clock[IO].timed[A](fa: IO[A]): IO[(FiniteDuration, A)]

/**
 * Current time since Unix epoch
 * @returns IO[FiniteDuration] with real time
 */
def Clock[IO].realTime: IO[FiniteDuration]

/**
 * Monotonic time for measuring intervals
 * @returns IO[FiniteDuration] with monotonic time
 */
def Clock[IO].monotonic: IO[FiniteDuration]

Duration Utilities

Working with duration values and time units.

// Import for duration syntax
import scala.concurrent.duration._

// Duration construction examples:
val oneSecond: FiniteDuration = 1.second
val fiveHundredMillis: FiniteDuration = 500.millis  
val twoMinutes: FiniteDuration = 2.minutes
val oneHour: FiniteDuration = 1.hour

// Duration operations
val total = 1.second + 500.millis
val half = 2.seconds / 2
val comparison = 1.second < 2.seconds

Usage Examples:

import cats.effect._
import scala.concurrent.duration._

// Basic sleep and delay
val sleepProgram = for {
  _    <- IO.println("Starting...")
  _    <- IO.sleep(1.second)
  _    <- IO.println("After 1 second")
} yield ()

// Timeout with fallback
val timeoutProgram = {
  val slowOperation = IO.sleep(5.seconds).as("Slow result")
  val fastFallback = IO.pure("Fast fallback")
  
  slowOperation.timeoutTo(2.seconds, fastFallback)
}

// Measuring execution time
val timedProgram = for {
  (duration, result) <- IO.delay {
    Thread.sleep(1000)
    "Computation result"  
  }.timed
  _ <- IO.println(s"Took ${duration.toMillis}ms: $result")
} yield result

// Fixed rate execution (runs every 30 seconds)
def healthCheck: IO[Unit] = 
  IO.println(s"Health check at ${java.time.Instant.now()}")

val healthMonitor = fixedRate(30.seconds)(healthCheck)

// Racing with timeout
val racingProgram = for {
  result <- IO.delay("Quick result").delayBy(100.millis)
             .raceTimeout(1.second)
  message = result match {
    case Left(())     => "Operation timed out"
    case Right(value) => s"Got result: $value"
  }
  _ <- IO.println(message)
} yield result

// Coordinated timing
val coordinatedProgram = for {
  start <- IO.monotonic
  _     <- IO.println("Starting coordinated operations")
  
  // Multiple operations with different timing
  fiber1 <- IO.sleep(500.millis).as("Task 1").start
  fiber2 <- IO.sleep(1.second).as("Task 2").start  
  fiber3 <- IO.sleep(1.5.seconds).as("Task 3").start
  
  // Wait for all to complete
  results <- List(fiber1, fiber2, fiber3)
              .traverse(_.joinWithNever)
  
  end <- IO.monotonic
  _ <- IO.println(s"All completed in ${(end - start).toMillis}ms")
  _ <- IO.println(s"Results: ${results.mkString(", ")}")
} yield results

// Retry with exponential backoff
def retryWithBackoff[A](
  operation: IO[A], 
  maxRetries: Int, 
  baseDelay: FiniteDuration
): IO[A] = {
  def attempt(retriesLeft: Int, delay: FiniteDuration): IO[A] = {
    operation.handleErrorWith { error =>
      if (retriesLeft > 0) {
        IO.println(s"Operation failed, retrying in ${delay.toMillis}ms...") >>
        IO.sleep(delay) >>
        attempt(retriesLeft - 1, delay * 2)
      } else {
        IO.raiseError(error)
      }
    }
  }
  
  attempt(maxRetries, baseDelay)
}

val retriedOperation = retryWithBackoff(
  operation = IO.raiseError(new RuntimeException("Flaky operation")),
  maxRetries = 3,
  baseDelay = 100.millis
)