scheduling
from andrueandersoncs/claude-skill-effect-ts
No description
2 stars0 forksUpdated Jan 25, 2026
npx skills add https://github.com/andrueandersoncs/claude-skill-effect-ts --skill schedulingSKILL.md
Scheduling in Effect
Overview
Effect's Schedule type describes patterns for:
- Retrying failed operations
- Repeating successful operations
- Polling at intervals
- Backoff strategies for resilience
Schedule<Out, In, Requirements>
// ^^^ ^^ Output and input types
Built-In Schedules
Fixed Intervals
import { Schedule } from "effect"
// Every 1 second
const everySecond = Schedule.spaced("1 second")
// Fixed delay between end and start
const fixed = Schedule.fixed("500 millis")
Recurrence Limits
// Exactly 5 times
const fiveTimes = Schedule.recurs(5)
// Once
const once = Schedule.once
// Forever
const forever = Schedule.forever
Exponential Backoff
// Exponential: 100ms, 200ms, 400ms, 800ms...
const exponential = Schedule.exponential("100 millis")
// With max delay cap
const capped = Schedule.exponential("100 millis").pipe(
Schedule.upTo("30 seconds")
)
// With jitter (randomization)
const jittered = Schedule.exponential("100 millis").pipe(
Schedule.jittered
)
Time-Based Limits
// Run for 1 minute
const forOneMinute = Schedule.spaced("1 second").pipe(
Schedule.upTo("1 minute")
)
// Until specific condition
const untilSuccess = Schedule.recurWhile(
(result) => result.status === "pending"
)
Using Schedules
Effect.retry - Retry on Failure
const resilientFetch = fetchData().pipe(
Effect.retry(
Schedule.exponential("1 second").pipe(
Schedule.compose(Schedule.recurs(5))
)
)
)
Effect.repeat - Repeat on Success
// Poll every 5 seconds
const polling = checkStatus().pipe(
Effect.repeat(Schedule.spaced("5 seconds"))
)
Effect.schedule - Full Control
const scheduled = effect.pipe(
Effect.schedule(mySchedule)
)
Schedule Combinators
Composing Schedules
// Both must allow (intersection)
const exponentialWithLimit = Schedule.exponential("1 second").pipe(
Schedule.compose(Schedule.recurs(10))
)
// Either allows (union)
const eitherSchedule = Schedule.union(
Schedule.spaced("1 second"),
Schedule.recurs(5)
)
Adding Jitter
// Random jitter ±20%
const jittered = Schedule.exponential("1 second").pipe(
Schedule.jittered
)
// Custom jitter
const customJitter = Schedule.exponential("1 second").pipe(
Schedule.jittered({ min: 0.8, max: 1.2 })
)
Delaying First Execution
// Wait before first attempt
const delayed = Schedule.spaced("1 second").pipe(
Schedule.delayed(() => "5 seconds")
)
Resetting Schedule
// Reset after 1 minute of no calls
const resetting = Schedule.exponential("1 second").pipe(
Schedule.resetAfter("1 minute")
)
Conditional Retrying
Retry While Condition
// Use Match.tag for error type checking in predicates
const retryTransient = effect.pipe(
Effect.retry({
schedule: Schedule.exponential("1 second"),
while: (error) =>
Match.value(error).pipe(
Match.tag("TransientError", () => true),
Match.orElse(() => false)
)
})
)
Retry Until Condition
// Stop retrying when a fatal error occurs
const retryUntilFatal = effect.pipe(
Effect.retry({
schedule: Schedule.recurs(10),
until: (error) =>
Match.value(error).pipe(
Match.tag("FatalError", () => true),
Match.orElse(() => false)
)
})
)
Cron Scheduling
import { Cron } from "effect"
// Every day at midnight
const daily = Cron.parse("0 0 * * *")
// Every hour
const hourly = Cron.parse("0 * * * *")
// Use with schedule
const cronSchedule = Schedule.cron(daily)
Schedule Outputs
Schedules can produce values:
// Track elapsed time
const withElapsed = Schedule.elapsed
// Count iterations
const withCount = Schedule.count
// Collect inputs
const collecting = Schedule.collectAll<number>()
Using Schedule Output
const [result, elapsed] = yield* effect.pipe(
Effect.retry(
Schedule.exponential("1 second").pipe(
Schedule.compose(Schedule.elapsed)
)
)
)
console.log(`Took ${elapsed}ms after retries`)
Common Patterns
API Retry with Backoff
const apiCall = fetchFromApi().pipe(
Effect.retry(
Schedule.exponential("500 millis").pipe(
Schedule.jittered,
Schedule.compose(Schedule.recurs(5)),
Schedule.upTo("30 seconds")
)
)
)
Polling with Timeout
const poll = checkJobStatus(jobId).pipe(
Effect.repeat(
Schedule.spaced("2 seconds").pipe(
Schedule.upTo("5 minutes")
)
),
Effect.timeout("5 minutes")
)
Circuit Breaker Pattern
const circuitBreaker = (effect: Effect.Effect<A, E>) => {
let failures = 0
const maxFailures = 5
const resetTimeout = "30 seconds"
return effect.pipe(
Effect.retry(
...
Repository Stats
Stars2
Forks0
LicenseMIT License