Hyperlinkv0.8.0-beta.28

Schedule

Schedule.fibonacciconsteffect/Schedule.ts:1350
(one: Duration.Input): Schedule<Duration.Duration>

Schedule that always recurs, increasing delays by summing the preceding two delays (similar to the Fibonacci sequence). Returns the current duration between recurrences.

Example (Retrying with Fibonacci backoff)

import { Console, Data, Effect, Schedule } from "effect"

class RetryAttemptError extends Data.TaggedError("RetryAttemptError")<{ readonly message: string }> {}

// Basic Fibonacci schedule starting with 100ms
const fibSchedule = Schedule.fibonacci("100 millis")
// Delays: 100ms, 100ms, 200ms, 300ms, 500ms, 800ms, 1300ms, ...

// Retry with Fibonacci backoff for gradual increase
const retryWithFib = Effect.gen(function*() {
  let attempt = 0

  const result = yield* Effect.retry(
    Effect.gen(function*() {
      attempt++
      yield* Console.log(`Attempt ${attempt}`)

      if (attempt < 5) {
        return yield* Effect.fail(new RetryAttemptError({ message: `Attempt ${attempt} failed` }))
      }

      return `Success on attempt ${attempt}`
    }),
    Schedule.max([
      Schedule.fibonacci("50 millis"),
      Schedule.recurs(6) // Maximum 6 retries
    ]).pipe(
      Schedule.tap(({ output: delay }) => Console.log(`Next retry in ${delay}`))
    )
  )

  yield* Console.log(`Final result: ${result}`)
})

// Heartbeat with Fibonacci intervals (starts fast, gets slower)
const adaptiveHeartbeat = Effect.gen(function*() {
  yield* Console.log("Heartbeat")
  return "pulse"
}).pipe(
  Effect.repeat(
    Schedule.fibonacci("200 millis").pipe(
      Schedule.upTo({ times: 8 }) // First 8 heartbeats
    )
  )
)

// Fibonacci vs exponential comparison
const compareSchedules = Effect.gen(function*() {
  yield* Console.log("=== Fibonacci Delays ===")
  // 100ms, 100ms, 200ms, 300ms, 500ms, 800ms

  yield* Console.log("=== Exponential Delays ===")
  // 100ms, 200ms, 400ms, 800ms, 1600ms, 3200ms

  // Fibonacci grows more slowly than exponential
})
constructors
export const fibonacci = (one: Duration.Input): Schedule<Duration.Duration> => {
  const oneMillis = Duration.toMillis(Duration.fromInputUnsafe(one))
  return fromStep(effect.sync(() => {
    let a = 0
    let b = oneMillis
    return constant(effect.sync(() => {
      const next = a + b
      a = b
      b = next
      const duration = Duration.millis(next)
      return [duration, duration]
    }))
  }))
}