(expression: Cron.Cron): Schedule<
Duration.Duration,
unknown,
Cron.CronParseError
>
(expression: string, tz?: string | DateTime.TimeZone): Schedule<
Duration.Duration,
unknown,
Cron.CronParseError
>Returns a new Schedule that recurs on the specified Cron schedule and
outputs the duration between recurrences.
Example (Scheduling work with cron expressions)
import { Console, Data, Effect, Schedule } from "effect"
class ScheduledTaskError extends Data.TaggedError("ScheduledTaskError")<{ readonly message: string }> {}
// Run every minute
const everyMinute = Schedule.cron("* * * * *")
const minutelyProgram = Effect.gen(function*() {
yield* Effect.repeat(
Effect.gen(function*() {
yield* Console.log("Running minutely task")
return "minute"
}),
everyMinute.pipe(
Schedule.upTo({ times: 3 }), // Run only 3 times for demo
Schedule.tap(({ output: duration }) =>
Console.log(`Next execution in: ${duration}`)
)
)
)
})
// Run every day at 2:30 AM
const dailyBackup = Schedule.cron("30 2 * * *")
const backupProgram = Effect.gen(function*() {
yield* Effect.repeat(
Effect.gen(function*() {
yield* Console.log("Running daily backup...")
// Simulate backup process
yield* Effect.sleep("2 seconds")
yield* Console.log("Backup completed")
return "backup-done"
}),
dailyBackup.pipe(
Schedule.upTo({ times: 2 }) // Run 2 times for demo
)
)
})
// Run every Monday at 9:00 AM with timezone
const weeklyReport = Schedule.cron("0 9 * * 1", "America/New_York")
const reportProgram = Effect.gen(function*() {
yield* Effect.repeat(
Effect.gen(function*() {
yield* Console.log("Generating weekly report...")
const report = {
week: 42,
status: "ready" as const
}
yield* Console.log(`Report generated: ${JSON.stringify(report)}`)
return report
}),
weeklyReport.pipe(Schedule.upTo({ times: 1 }))
)
})
// Run every 15 minutes during business hours (9 AM - 5 PM)
const businessHoursCheck = Schedule.cron("0,15,30,45 9-17 * * 1-5")
const businessProgram = Effect.gen(function*() {
const statuses = ["healthy", "healthy", "degraded", "healthy"] as const
let index = 0
yield* Effect.repeat(
Effect.gen(function*() {
yield* Console.log("Business hours health check...")
const status = statuses[index++]
yield* Console.log(`System status: ${status}`)
return status
}),
businessHoursCheck.pipe(
Schedule.upTo({ times: 4 }) // Demo with 4 checks
)
)
})
// Run on specific days of the month
const monthlyInvoice = Schedule.cron("0 10 1,15 * *") // 1st and 15th at 10 AM
const invoiceProgram = Effect.gen(function*() {
yield* Effect.repeat(
Effect.gen(function*() {
yield* Console.log("Processing monthly invoices...")
const invoiceCount = 72
yield* Console.log(`Processed ${invoiceCount} invoices`)
return { count: invoiceCount, batch: "2024-01-a" }
}),
monthlyInvoice.pipe(Schedule.upTo({ times: 1 }))
)
})
// Complex cron with error handling
const complexCron = Schedule.cron("0 2,4,6 * * *").pipe(
Schedule.tap(({ output: duration }) =>
Console.log(`Scheduled to run again in ${duration}`)
)
)
const robustProgram = Effect.gen(function*() {
let attempt = 0
yield* Effect.repeat(
Effect.gen(function*() {
attempt++
yield* Console.log("Complex scheduled task...")
if (attempt === 1) {
return yield* Effect.fail(new ScheduledTaskError({ message: "Scheduled task failed" }))
}
return "success"
}),
complexCron.pipe(Schedule.upTo({ times: 3 }))
).pipe(
Effect.catch((error: unknown) =>
Console.log(`Cron task error: ${String(error)}`)
)
)
})export const const cron: {
(expression: Cron.Cron): Schedule<
Duration.Duration,
unknown,
Cron.CronParseError
>
(
expression: string,
tz?: string | DateTime.TimeZone
): Schedule<
Duration.Duration,
unknown,
Cron.CronParseError
>
}
Returns a new Schedule that recurs on the specified Cron schedule and
outputs the duration between recurrences.
Example (Scheduling work with cron expressions)
import { Console, Data, Effect, Schedule } from "effect"
class ScheduledTaskError extends Data.TaggedError("ScheduledTaskError")<{ readonly message: string }> {}
// Run every minute
const everyMinute = Schedule.cron("* * * * *")
const minutelyProgram = Effect.gen(function*() {
yield* Effect.repeat(
Effect.gen(function*() {
yield* Console.log("Running minutely task")
return "minute"
}),
everyMinute.pipe(
Schedule.upTo({ times: 3 }), // Run only 3 times for demo
Schedule.tap(({ output: duration }) =>
Console.log(`Next execution in: ${duration}`)
)
)
)
})
// Run every day at 2:30 AM
const dailyBackup = Schedule.cron("30 2 * * *")
const backupProgram = Effect.gen(function*() {
yield* Effect.repeat(
Effect.gen(function*() {
yield* Console.log("Running daily backup...")
// Simulate backup process
yield* Effect.sleep("2 seconds")
yield* Console.log("Backup completed")
return "backup-done"
}),
dailyBackup.pipe(
Schedule.upTo({ times: 2 }) // Run 2 times for demo
)
)
})
// Run every Monday at 9:00 AM with timezone
const weeklyReport = Schedule.cron("0 9 * * 1", "America/New_York")
const reportProgram = Effect.gen(function*() {
yield* Effect.repeat(
Effect.gen(function*() {
yield* Console.log("Generating weekly report...")
const report = {
week: 42,
status: "ready" as const
}
yield* Console.log(`Report generated: ${JSON.stringify(report)}`)
return report
}),
weeklyReport.pipe(Schedule.upTo({ times: 1 }))
)
})
// Run every 15 minutes during business hours (9 AM - 5 PM)
const businessHoursCheck = Schedule.cron("0,15,30,45 9-17 * * 1-5")
const businessProgram = Effect.gen(function*() {
const statuses = ["healthy", "healthy", "degraded", "healthy"] as const
let index = 0
yield* Effect.repeat(
Effect.gen(function*() {
yield* Console.log("Business hours health check...")
const status = statuses[index++]
yield* Console.log(`System status: ${status}`)
return status
}),
businessHoursCheck.pipe(
Schedule.upTo({ times: 4 }) // Demo with 4 checks
)
)
})
// Run on specific days of the month
const monthlyInvoice = Schedule.cron("0 10 1,15 * *") // 1st and 15th at 10 AM
const invoiceProgram = Effect.gen(function*() {
yield* Effect.repeat(
Effect.gen(function*() {
yield* Console.log("Processing monthly invoices...")
const invoiceCount = 72
yield* Console.log(`Processed ${invoiceCount} invoices`)
return { count: invoiceCount, batch: "2024-01-a" }
}),
monthlyInvoice.pipe(Schedule.upTo({ times: 1 }))
)
})
// Complex cron with error handling
const complexCron = Schedule.cron("0 2,4,6 * * *").pipe(
Schedule.tap(({ output: duration }) =>
Console.log(`Scheduled to run again in ${duration}`)
)
)
const robustProgram = Effect.gen(function*() {
let attempt = 0
yield* Effect.repeat(
Effect.gen(function*() {
attempt++
yield* Console.log("Complex scheduled task...")
if (attempt === 1) {
return yield* Effect.fail(new ScheduledTaskError({ message: "Scheduled task failed" }))
}
return "success"
}),
complexCron.pipe(Schedule.upTo({ times: 3 }))
).pipe(
Effect.catch((error: unknown) =>
Console.log(`Cron task error: ${String(error)}`)
)
)
})
cron: {
(expression: Cron.Cron(parameter) expression: {
tz: Option.Option<DateTime.TimeZone>;
seconds: ReadonlySet<number>;
minutes: ReadonlySet<number>;
hours: ReadonlySet<number>;
days: ReadonlySet<number>;
months: ReadonlySet<number>;
weekdays: ReadonlySet<number>;
and: boolean;
first: { readonly second: number; readonly minute: number; readonly hour: number; readonly day: number; readonly month: number; readonly weekday: number };
last: { readonly second: number; readonly minute: number; readonly hour: number; readonly day: number; readonly month: number; readonly weekday: number };
next: { readonly second: ReadonlyArray<number | undefined>; readonly minute: ReadonlyArray<number | undefined>; readonly hour: ReadonlyArray<number | undefined>; readonly day: ReadonlyArray<number | undefined>; readonly month: ReadonlyArray<numb…;
prev: { readonly second: ReadonlyArray<number | undefined>; readonly minute: ReadonlyArray<number | undefined>; readonly hour: ReadonlyArray<number | undefined>; readonly day: ReadonlyArray<number | undefined>; readonly month: ReadonlyArray<numb…;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
expression: import CronCron.type Cron.Cron = /*unresolved*/ anyCron): interface Schedule<out Output, in Input = unknown, out Error = never, out Env = never>A Schedule defines a strategy for repeating or retrying effects based on some policy.
Example (Defining retry and repeat schedules)
import { Console, Data, Effect, Schedule } from "effect"
class NetworkError extends Data.TaggedError("NetworkError")<{
readonly attempt: number
}> {}
// Basic retry schedule - retry up to 3 times with exponential backoff
const retrySchedule = Schedule.max([
Schedule.exponential("100 millis"),
Schedule.recurs(3)
])
// Basic repeat schedule - repeat every 30 seconds forever
const repeatSchedule: Schedule.Schedule<number, unknown, never> = Schedule
.spaced("30 seconds")
const program = Effect.gen(function*() {
let attempts = 0
const result1 = yield* Effect.retry(
Effect.gen(function*() {
attempts++
if (attempts < 3) {
return yield* Effect.fail(new NetworkError({ attempt: attempts }))
}
return "Success"
}),
retrySchedule
)
console.log(result1) // "Success"
yield* Console.log("heartbeat").pipe(
Effect.repeat(repeatSchedule.pipe(Schedule.upTo({ times: 5 })))
)
})
The Schedule namespace contains types and utilities for working with schedules.
Schedule<import DurationDuration.type Duration.Duration = /*unresolved*/ anyDuration, unknown, import CronCron.type Cron.CronParseError = /*unresolved*/ anyCronParseError>
(expression: stringexpression: string, tz: string | DateTime.TimeZonetz?: string | import DateTimeDateTime.type DateTime.TimeZone = /*unresolved*/ anyTimeZone): interface Schedule<out Output, in Input = unknown, out Error = never, out Env = never>A Schedule defines a strategy for repeating or retrying effects based on some policy.
Example (Defining retry and repeat schedules)
import { Console, Data, Effect, Schedule } from "effect"
class NetworkError extends Data.TaggedError("NetworkError")<{
readonly attempt: number
}> {}
// Basic retry schedule - retry up to 3 times with exponential backoff
const retrySchedule = Schedule.max([
Schedule.exponential("100 millis"),
Schedule.recurs(3)
])
// Basic repeat schedule - repeat every 30 seconds forever
const repeatSchedule: Schedule.Schedule<number, unknown, never> = Schedule
.spaced("30 seconds")
const program = Effect.gen(function*() {
let attempts = 0
const result1 = yield* Effect.retry(
Effect.gen(function*() {
attempts++
if (attempts < 3) {
return yield* Effect.fail(new NetworkError({ attempt: attempts }))
}
return "Success"
}),
retrySchedule
)
console.log(result1) // "Success"
yield* Console.log("heartbeat").pipe(
Effect.repeat(repeatSchedule.pipe(Schedule.upTo({ times: 5 })))
)
})
The Schedule namespace contains types and utilities for working with schedules.
Schedule<import DurationDuration.type Duration.Duration = /*unresolved*/ anyDuration, unknown, import CronCron.type Cron.CronParseError = /*unresolved*/ anyCronParseError>
} = (expression: string | Cron.Cronexpression: string | import CronCron.type Cron.Cron = /*unresolved*/ anyCron, tz: string | DateTime.TimeZonetz?: string | import DateTimeDateTime.type DateTime.TimeZone = /*unresolved*/ anyTimeZone) => {
const const parsed: anyparsed = import CronCron.isCron(expression: string | Cron.Cronexpression) ? import ResultResult.succeed(expression: string | Cron.Cron(parameter) expression: {
tz: Option.Option<DateTime.TimeZone>;
seconds: ReadonlySet<number>;
minutes: ReadonlySet<number>;
hours: ReadonlySet<number>;
days: ReadonlySet<number>;
months: ReadonlySet<number>;
weekdays: ReadonlySet<number>;
and: boolean;
first: { readonly second: number; readonly minute: number; readonly hour: number; readonly day: number; readonly month: number; readonly weekday: number };
last: { readonly second: number; readonly minute: number; readonly hour: number; readonly day: number; readonly month: number; readonly weekday: number };
next: { readonly second: ReadonlyArray<number | undefined>; readonly minute: ReadonlyArray<number | undefined>; readonly hour: ReadonlyArray<number | undefined>; readonly day: ReadonlyArray<number | undefined>; readonly month: ReadonlyArray<numb…;
prev: { readonly second: ReadonlyArray<number | undefined>; readonly minute: ReadonlyArray<number | undefined>; readonly hour: ReadonlyArray<number | undefined>; readonly day: ReadonlyArray<number | undefined>; readonly month: ReadonlyArray<numb…;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
expression) : import CronCron.parse(expression: string | Cron.Cronexpression, tz: string | DateTime.TimeZonetz)
return const fromStep: <
Input,
Output,
EnvX,
Error,
ErrorX,
Env
>(
step: Effect<
(
now: number,
input: Input
) => Pull.Pull<
[Output, Duration.Duration],
ErrorX,
Output,
EnvX
>,
Error,
Env
>
) => Schedule<
Output,
Input,
Error | Pull.ExcludeDone<ErrorX>,
Env | EnvX
>
Creates a Schedule from a step function that returns a Pull.
Example (Creating a custom schedule from a step function)
import { Cause, Duration, Effect, Schedule } from "effect"
const schedule = Schedule.fromStep(Effect.sync(() => {
let count = 0
return (_now: number, _input: string) => {
if (count >= 3) {
return Cause.done(count)
}
return Effect.succeed([count++, Duration.millis(100)] as [number, Duration.Duration])
}
}))
fromStep(import effecteffect.const map: {
<A, B>(f: (a: A) => B): <E, R>(
self: Effect.Effect<A, E, R>
) => Effect.Effect<B, E, R>
<A, E, R, B>(
self: Effect.Effect<A, E, R>,
f: (a: A) => B
): Effect.Effect<B, E, R>
}
map(import effecteffect.const fromResult: <A, E>(
result: Result.Result<A, E>
) => Effect.Effect<A, E>
fromResult(const parsed: anyparsed), (cron: Cron.Cron(parameter) cron: {
tz: Option.Option<DateTime.TimeZone>;
seconds: ReadonlySet<number>;
minutes: ReadonlySet<number>;
hours: ReadonlySet<number>;
days: ReadonlySet<number>;
months: ReadonlySet<number>;
weekdays: ReadonlySet<number>;
and: boolean;
first: { readonly second: number; readonly minute: number; readonly hour: number; readonly day: number; readonly month: number; readonly weekday: number };
last: { readonly second: number; readonly minute: number; readonly hour: number; readonly day: number; readonly month: number; readonly weekday: number };
next: { readonly second: ReadonlyArray<number | undefined>; readonly minute: ReadonlyArray<number | undefined>; readonly hour: ReadonlyArray<number | undefined>; readonly day: ReadonlyArray<number | undefined>; readonly month: ReadonlyArray<numb…;
prev: { readonly second: ReadonlyArray<number | undefined>; readonly minute: ReadonlyArray<number | undefined>; readonly hour: ReadonlyArray<number | undefined>; readonly day: ReadonlyArray<number | undefined>; readonly month: ReadonlyArray<numb…;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
cron) => (now: anynow, _: any_) => {
if (now: anynow === var Number: NumberConstructorAn object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number.NumberConstructor.POSITIVE_INFINITY: numberA value greater than the largest number that can be represented in JavaScript.
JavaScript displays POSITIVE_INFINITY values as infinity.
POSITIVE_INFINITY) {
return import CauseCause.done(import DurationDuration.zero)
}
return import effecteffect.const sync: <A>(
thunk: LazyArg<A>
) => Effect.Effect<A>
sync(() => {
const const next: anynext = import CronCron.next(cron: Cron.Cron(parameter) cron: {
tz: Option.Option<DateTime.TimeZone>;
seconds: ReadonlySet<number>;
minutes: ReadonlySet<number>;
hours: ReadonlySet<number>;
days: ReadonlySet<number>;
months: ReadonlySet<number>;
weekdays: ReadonlySet<number>;
and: boolean;
first: { readonly second: number; readonly minute: number; readonly hour: number; readonly day: number; readonly month: number; readonly weekday: number };
last: { readonly second: number; readonly minute: number; readonly hour: number; readonly day: number; readonly month: number; readonly weekday: number };
next: { readonly second: ReadonlyArray<number | undefined>; readonly minute: ReadonlyArray<number | undefined>; readonly hour: ReadonlyArray<number | undefined>; readonly day: ReadonlyArray<number | undefined>; readonly month: ReadonlyArray<numb…;
prev: { readonly second: ReadonlyArray<number | undefined>; readonly minute: ReadonlyArray<number | undefined>; readonly hour: ReadonlyArray<number | undefined>; readonly day: ReadonlyArray<number | undefined>; readonly month: ReadonlyArray<numb…;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
cron, now: anynow).getTime()
const const duration: Duration.Durationconst duration: {
value: DurationValue;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
duration = import DurationDuration.millis(const next: anynext - now: anynow)
return [const duration: Duration.Durationconst duration: {
value: DurationValue;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
duration, const duration: Duration.Durationconst duration: {
value: DurationValue;
pipe: { <A>(this: A): A; <A, B = never>(this: A, ab: (_: A) => B): B; <A, B = never, C = never>(this: A, ab: (_: A) => B, bc: (_: B) => C): C; <A, B = never, C = never, D = never>(this: A, ab: (_: A) => B, bc: (_: B) => C, cd: (_: C) => D): D; <…;
toString: () => string;
toJSON: () => unknown;
}
duration]
})
}))
}