Skip to content

Cron

Cron 模块让你可以定义类似于 UNIX cron 表达式 风格的调度。 它还支持部分约束(例如,特定月份或工作日)、通过 DateTime 模块的时区感知以及强大的错误处理。

此模块帮助你:

  • 创建 从各个部分构建的 Cron 实例。
  • 解析和验证 cron 表达式。
  • 匹配 现有日期以查看它们是否满足给定的 cron 调度。
  • 查找 给定日期后调度的下一次出现。
  • 迭代 匹配调度的未来日期。
  • 转换 Cron 实例为 Schedule 以在有副作用的程序中使用。

你可以通过为秒、分钟、小时、天、月和工作日指定数字约束来定义 cron 调度。make 函数要求你定义表示调度约束的所有字段。

示例(创建 Cron)

import {
import Cron
Cron
,
import DateTime
DateTime
} from "effect"
// 构建一个在每月8日到14日
// 凌晨4:00触发的cron
const
const cron: Cron.Cron
cron
=
import Cron
Cron
.
const make: (values: {
readonly seconds?: Iterable<number> | undefined;
readonly minutes: Iterable<number>;
readonly hours: Iterable<number>;
readonly days: Iterable<number>;
readonly months: Iterable<number>;
readonly weekdays: Iterable<number>;
readonly tz?: DateTime.TimeZone | undefined;
}) => Cron.Cron

Creates a Cron instance.

@since2.0.0

make
({
seconds?: Iterable<number> | undefined
seconds
: [0], // 在分钟开始时触发
minutes: Iterable<number>
minutes
: [0], // 在小时开始时触发
hours: Iterable<number>
hours
: [4], // 在凌晨4:00触发
days: Iterable<number>
days
: [8, 9, 10, 11, 12, 13, 14], // 月份的特定日期
months: Iterable<number>
months
: [], // 对月份没有限制
weekdays: Iterable<number>
weekdays
: [], // 对工作日没有限制
tz?: DateTime.TimeZone | undefined
tz
:
import DateTime
DateTime
.
const zoneUnsafeMakeNamed: (zoneId: string) => DateTime.TimeZone.Named

Attempt to create a named time zone from a IANA time zone identifier.

If the time zone is invalid, an IllegalArgumentException will be thrown.

@since3.6.0

zoneUnsafeMakeNamed
("Europe/Rome") // 可选的时区
})
  • secondsminuteshours:定义一天中的时间。
  • daysmonths:指定哪些日历日期和月份是有效的。
  • weekdays:将调度限制为一周中的特定日期。
  • tz:可选地为调度定义时区。

如果任何字段留空(例如 months),它被视为”无约束”,允许日期的该部分使用任何有效值。

你可以使用类似 UNIX 的 cron 字符串并使用 parseunsafeParse 解析它们,而不是手动构造 Cron

parse(cronExpression, tz?) 函数安全地将 cron 字符串解析为 Cron 实例。它返回一个 Either,其中包含解析的 Cron 或解析错误。

示例(安全解析 Cron 表达式)

import {
import Either

@since2.0.0

@since2.0.0

Either
,
import Cron
Cron
} from "effect"
// 定义一个在每月8日到14日
// 凌晨4:00的cron表达式
const
const expression: "0 0 4 8-14 * *"
expression
= "0 0 4 8-14 * *"
// 解析cron表达式
const
const eitherCron: Either.Either<Cron.Cron, Cron.ParseError>
eitherCron
=
import Cron
Cron
.
const parse: (cron: string, tz?: TimeZone | string) => Either.Either<Cron.Cron, Cron.ParseError>

Parses a cron expression into a Cron instance.

@example

import * as assert from "node:assert"
import { Cron, Either } from "effect"
// At 04:00 on every day-of-month from 8 through 14.
assert.deepStrictEqual(Cron.parse("0 0 4 8-14 * *"), Either.right(Cron.make({
seconds: [0],
minutes: [0],
hours: [4],
days: [8, 9, 10, 11, 12, 13, 14],
months: [],
weekdays: []
})))

@since2.0.0

parse
(
const expression: "0 0 4 8-14 * *"
expression
)
if (
import Either

@since2.0.0

@since2.0.0

Either
.
const isRight: <Cron.Cron, Cron.ParseError>(self: Either.Either<Cron.Cron, Cron.ParseError>) => self is Either.Right<Cron.ParseError, Cron.Cron>

Determine if a Either is a Right.

@example

import * as assert from "node:assert"
import { Either } from "effect"
assert.deepStrictEqual(Either.isRight(Either.right(1)), true)
assert.deepStrictEqual(Either.isRight(Either.left("a")), false)

@since2.0.0

isRight
(
const eitherCron: Either.Either<Cron.Cron, Cron.ParseError>
eitherCron
)) {
// 解析成功
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("Parsed cron:",
const eitherCron: Either.Right<Cron.ParseError, Cron.Cron>
eitherCron
.
Right<ParseError, Cron>.right: Cron.Cron
right
)
} else {
// 解析失败
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.error(message?: any, ...optionalParams: any[]): void

Prints to stderr with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const code = 5;
console.error('error #%d', code);
// Prints: error #5, to stderr
console.error('error', code);
// Prints: error 5, to stderr

If formatting elements (e.g. %d) are not found in the first string then util.inspect() is called on each argument and the resulting string values are concatenated. See util.format() for more information.

@sincev0.1.100

error
("Failed to parse cron:",
const eitherCron: Either.Left<Cron.ParseError, Cron.Cron>
eitherCron
.
Left<ParseError, Cron>.left: Cron.ParseError
left
.
Error.message: string
message
)
}

unsafeParse(cronExpression, tz?) 函数的工作方式类似于 parse,但不是返回 Either,而是在输入无效时抛出异常。

示例(解析 Cron 表达式)

import {
import Cron
Cron
} from "effect"
// 解析一个在每月8日到14日
// 凌晨4:00的cron表达式
// 如果表达式无效则抛出异常
const
const cron: Cron.Cron
cron
=
import Cron
Cron
.
const unsafeParse: (cron: string, tz?: TimeZone | string) => Cron.Cron

Parses a cron expression into a Cron instance.

Details

This function takes a cron expression as a string and attempts to parse it into a Cron instance. If the expression is valid, the resulting Cron instance will represent the schedule defined by the cron expression.

If the expression is invalid, the function throws a ParseError.

You can optionally provide a time zone (tz) to interpret the cron expression in a specific time zone. If no time zone is provided, the cron expression will use the default time zone.

@example

import { Cron } from "effect"
// At 04:00 on every day-of-month from 8 through 14.
console.log(Cron.unsafeParse("0 4 8-14 * *"))
// Output:
// {
// _id: 'Cron',
// tz: { _id: 'Option', _tag: 'None' },
// seconds: [ 0 ],
// minutes: [ 0 ],
// hours: [ 4 ],
// days: [
// 8, 9, 10, 11,
// 12, 13, 14
// ],
// months: [],
// weekdays: []
// }

@since2.0.0

unsafeParse
("0 0 4 8-14 * *")

match 函数允许你确定给定的 Date(或任何 DateTime.Input)是否满足 cron 调度的约束。

如果日期满足调度的条件,match 返回 true。否则,它返回 false

示例(检查日期是否匹配 Cron 调度)

import {
import Cron
Cron
} from "effect"
// 假设我们有一个在每月8日到14日
// 凌晨4:00触发的cron
const
const cron: Cron.Cron
cron
=
import Cron
Cron
.
const unsafeParse: (cron: string, tz?: TimeZone | string) => Cron.Cron

Parses a cron expression into a Cron instance.

Details

This function takes a cron expression as a string and attempts to parse it into a Cron instance. If the expression is valid, the resulting Cron instance will represent the schedule defined by the cron expression.

If the expression is invalid, the function throws a ParseError.

You can optionally provide a time zone (tz) to interpret the cron expression in a specific time zone. If no time zone is provided, the cron expression will use the default time zone.

@example

import { Cron } from "effect"
// At 04:00 on every day-of-month from 8 through 14.
console.log(Cron.unsafeParse("0 4 8-14 * *"))
// Output:
// {
// _id: 'Cron',
// tz: { _id: 'Option', _tag: 'None' },
// seconds: [ 0 ],
// minutes: [ 0 ],
// hours: [ 4 ],
// days: [
// 8, 9, 10, 11,
// 12, 13, 14
// ],
// months: [],
// weekdays: []
// }

@since2.0.0

unsafeParse
("0 0 4 8-14 * *")
const
const checkDate: Date
checkDate
= new
var Date: DateConstructor
new (value: number | string | Date) => Date (+3 overloads)
Date
("2025-01-08 04:00:00")
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
(
import Cron
Cron
.
const match: (cron: Cron.Cron, date: DateTime.Input) => boolean

Checks if a given Date falls within an active Cron time window.

@example

import * as assert from "node:assert"
import { Cron, Either } from "effect"
const cron = Either.getOrThrow(Cron.parse("0 4 8-14 * *"))
assert.deepStrictEqual(Cron.match(cron, new Date("2021-01-08 04:00:00")), true)
assert.deepStrictEqual(Cron.match(cron, new Date("2021-01-08 05:00:00")), false)

@throwsIllegalArgumentException if the given DateTime.Input is invalid.

@since2.0.0

match
(
const cron: Cron.Cron
cron
,
const checkDate: Date
checkDate
))
// 输出: true

next 函数确定满足给定 cron 调度的下一个日期,从指定日期开始。如果没有提供起始日期,则使用当前时间作为起点。

如果 next 在预定义的迭代次数内无法找到匹配的日期,它会抛出错误以防止无限循环。

示例(确定下一个匹配日期)

import {
import Cron
Cron
} from "effect"
// 定义一个在每月8日到14日
// 凌晨4:00的cron表达式
const
const cron: Cron.Cron
cron
=
import Cron
Cron
.
const unsafeParse: (cron: string, tz?: TimeZone | string) => Cron.Cron

Parses a cron expression into a Cron instance.

Details

This function takes a cron expression as a string and attempts to parse it into a Cron instance. If the expression is valid, the resulting Cron instance will represent the schedule defined by the cron expression.

If the expression is invalid, the function throws a ParseError.

You can optionally provide a time zone (tz) to interpret the cron expression in a specific time zone. If no time zone is provided, the cron expression will use the default time zone.

@example

import { Cron } from "effect"
// At 04:00 on every day-of-month from 8 through 14.
console.log(Cron.unsafeParse("0 4 8-14 * *"))
// Output:
// {
// _id: 'Cron',
// tz: { _id: 'Option', _tag: 'None' },
// seconds: [ 0 ],
// minutes: [ 0 ],
// hours: [ 4 ],
// days: [
// 8, 9, 10, 11,
// 12, 13, 14
// ],
// months: [],
// weekdays: []
// }

@since2.0.0

unsafeParse
("0 0 4 8-14 * *", "UTC")
// 指定搜索的起点
const
const after: Date
after
= new
var Date: DateConstructor
new (value: number | string | Date) => Date (+3 overloads)
Date
("2025-01-08")
// 查找下一个匹配日期
const
const nextDate: Date
nextDate
=
import Cron
Cron
.
const next: (cron: Cron.Cron, startFrom?: DateTime.Input) => Date

Returns the next run Date for the given Cron instance.

Uses the current time as a starting point if no value is provided for now.

@example

import * as assert from "node:assert"
import { Cron, Either } from "effect"
const after = new Date("2021-01-01 00:00:00")
const cron = Either.getOrThrow(Cron.parse("0 4 8-14 * *"))
assert.deepStrictEqual(Cron.next(cron, after), new Date("2021-01-08 04:00:00"))

@throwsIllegalArgumentException if the given DateTime.Input is invalid.

@throwsError if the next run date cannot be found within 10,000 iterations.

@since2.0.0

next
(
const cron: Cron.Cron
cron
,
const after: Date
after
)
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
(
const nextDate: Date
nextDate
)
// 输出: 2025-01-08T04:00:00.000Z

要生成匹配 cron 调度的多个未来日期,你可以使用 sequence 函数。此函数提供匹配日期的无限迭代器,从指定日期开始。

示例(使用迭代器生成未来日期)

import { Cron } from "effect"
// 定义一个在每月8日到14日
// 凌晨4:00的cron表达式
const cron = Cron.unsafeParse("0 0 4 8-14 * *", "UTC")
// 指定起始日期
const start = new Date("2021-01-08")
// 为调度创建迭代器
const iterator = Cron.sequence(cron, start)
// 获取起始日期后的第一个匹配日期
console.log(iterator.next().value)
// 输出: 2021-01-08T04:00:00.000Z
// 获取起始日期后的第二个匹配日期
console.log(iterator.next().value)
// 输出: 2021-01-09T04:00:00.000Z

Schedule 模块允许你定义重复行为,例如重试或周期性事件。cron 函数在 Cron 模块和 Schedule 模块之间架起桥梁,使你能够基于 cron 表达式或 Cron 实例创建调度。

Schedule.cron 函数生成一个 Schedule,它在由提供的 cron 表达式或 Cron 实例定义的每个间隔开始时触发。触发时,调度产生一个元组 [start, end],表示 cron 间隔窗口的时间戳(以毫秒为单位)。

示例(从 Cron 创建 Schedule)

import {
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
,
import Schedule
Schedule
,
import TestClock
TestClock
,
import Fiber
Fiber
,
import TestContext
TestContext
,
import Cron
Cron
,
import Console
Console
} from "effect"
// 一个在调度的每个间隔记录输出的辅助函数
29 collapsed lines
const
const log: <A>(action: Effect.Effect<A>, schedule: Schedule.Schedule<[number, number], void>) => void
log
= <
function (type parameter) A in <A>(action: Effect.Effect<A>, schedule: Schedule.Schedule<[number, number], void>): void
A
>(
action: Effect.Effect<A, never, never>
action
:
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
interface Effect<out A, out E = never, out R = never>

The Effect interface defines a value that describes a workflow or job, which can succeed or fail.

Details

The Effect interface represents a computation that can model a workflow involving various types of operations, such as synchronous, asynchronous, concurrent, and parallel interactions. It operates within a context of type R, and the result can either be a success with a value of type A or a failure with an error of type E. The Effect is designed to handle complex interactions with external resources, offering advanced features such as fiber-based concurrency, scheduling, interruption handling, and scalability. This makes it suitable for tasks that require fine-grained control over concurrency and error management.

To execute an Effect value, you need a Runtime, which provides the environment necessary to run and manage the computation.

@since2.0.0

@since2.0.0

Effect
<
function (type parameter) A in <A>(action: Effect.Effect<A>, schedule: Schedule.Schedule<[number, number], void>): void
A
>,
schedule: Schedule.Schedule<[number, number], void, never>
schedule
:
import Schedule
Schedule
.
interface Schedule<out Out, in In = unknown, out R = never>

A Schedule<Out, In, R> defines a recurring schedule, which consumes values of type In, and which returns values of type Out.

The Schedule type is structured as follows:

// ┌─── The type of output produced by the schedule
// │ ┌─── The type of input consumed by the schedule
// │ │ ┌─── Additional requirements for the schedule
// ▼ ▼ ▼
Schedule<Out, In, Requirements>

A schedule operates by consuming values of type In (such as errors in the case of Effect.retry, or values in the case of Effect.repeat) and producing values of type Out. It determines when to halt or continue the execution based on input values and its internal state.

The inclusion of a Requirements parameter allows the schedule to leverage additional services or resources as needed.

Schedules are defined as a possibly infinite set of intervals spread out over time. Each interval defines a window in which recurrence is possible.

When schedules are used to repeat or retry effects, the starting boundary of each interval produced by a schedule is used as the moment when the effect will be executed again.

Schedules can be composed in different ways:

  • Union: Combines two schedules and recurs if either schedule wants to continue, using the shorter delay.
  • Intersection: Combines two schedules and recurs only if both schedules want to continue, using the longer delay.
  • Sequencing: Combines two schedules by running the first one fully, then switching to the second.

In addition, schedule inputs and outputs can be transformed, filtered (to terminate a schedule early in response to some input or output), and so forth.

A variety of other operators exist for transforming and combining schedules, and the companion object for Schedule contains all common types of schedules, both for performing retrying, as well as performing repetition.

@since2.0.0

@since2.0.0

Schedule
<[number, number], void>
): void => {
let
let i: number
i
= 0
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<void, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<void, never, never>>, void, never>) => Effect.Effect<void, never, never> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
const
const fiber: Fiber.RuntimeFiber<[[number, number], number], never>
fiber
:
import Fiber
Fiber
.
interface RuntimeFiber<out A, out E = never>

A runtime fiber that is executing an effect. Runtime fibers have an identity and a trace.

@since2.0.0

RuntimeFiber
<[[number, number], number]> =
yield*
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const gen: <YieldWrap<Effect.Effect<A, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<A, never, never>>, void, never>) => Effect.Effect<void, never, never> (+1 overload)

Provides a way to write effectful code using generator functions, simplifying control flow and error handling.

When to Use

Effect.gen allows you to write code that looks and behaves like synchronous code, but it can handle asynchronous tasks, errors, and complex control flow (like loops and conditions). It helps make asynchronous code more readable and easier to manage.

The generator functions work similarly to async/await but with more explicit control over the execution of effects. You can yield* values from effects and return the final result at the end.

Example

import { Effect } from "effect"
const addServiceCharge = (amount: number) => amount + 1
const applyDiscount = (
total: number,
discountRate: number
): Effect.Effect<number, Error> =>
discountRate === 0
? Effect.fail(new Error("Discount rate cannot be zero"))
: Effect.succeed(total - (total * discountRate) / 100)
const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
const fetchDiscountRate = Effect.promise(() => Promise.resolve(5))
export const program = Effect.gen(function* () {
const transactionAmount = yield* fetchTransactionAmount
const discountRate = yield* fetchDiscountRate
const discountedAmount = yield* applyDiscount(
transactionAmount,
discountRate
)
const finalAmount = addServiceCharge(discountedAmount)
return `Final amount to charge: ${finalAmount}`
})

@since2.0.0

gen
(function* () {
yield*
action: Effect.Effect<A, never, never>
action
let i: number
i
++
}).
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<[[number, number], number], never, never>, Effect.Effect<Fiber.RuntimeFiber<[[number, number], number], never>, never, never>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<[[number, number], number], never, never>, bc: (_: Effect.Effect<[[number, number], number], never, never>) => Effect.Effect<Fiber.RuntimeFiber<[[number, number], number], never>, never, never>): Effect.Effect<...> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const repeat: <[[number, number], number], void, never>(schedule: Schedule.Schedule<[[number, number], number], void, never>) => <E, R>(self: Effect.Effect<void, E, R>) => Effect.Effect<[[number, number], number], E, R> (+3 overloads)

Repeats an effect based on a specified schedule or until the first failure.

Details

This function executes an effect repeatedly according to the given schedule. Each repetition occurs after the initial execution of the effect, meaning that the schedule determines the number of additional repetitions. For example, using Schedule.once will result in the effect being executed twice (once initially and once as part of the repetition).

If the effect succeeds, it is repeated according to the schedule. If it fails, the repetition stops immediately, and the failure is returned.

The schedule can also specify delays between repetitions, making it useful for tasks like retrying operations with backoff, periodic execution, or performing a series of dependent actions.

You can combine schedules for more advanced repetition logic, such as adding delays, limiting recursions, or dynamically adjusting based on the outcome of each execution.

Example (Success Example)

import { Effect, Schedule, Console } from "effect"
const action = Console.log("success")
const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis")
const program = Effect.repeat(action, policy)
Effect.runPromise(program).then((n) => console.log(`repetitions: ${n}`))

Example (Failure Example)

import { Effect, Schedule } from "effect"
let count = 0
// Define an async effect that simulates an action with possible failures
const action = Effect.async<string, string>((resume) => {
if (count > 1) {
console.log("failure")
resume(Effect.fail("Uh oh!"))
} else {
count++
console.log("success")
resume(Effect.succeed("yay!"))
}
})
const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis")
const program = Effect.repeat(action, policy)
Effect.runPromiseExit(program).then(console.log)

@since2.0.0

repeat
(
schedule: Schedule.Schedule<[number, number], void, never>
schedule
.
Pipeable.pipe<Schedule.Schedule<[number, number], void, never>, Schedule.Schedule<[[number, number], number], void, never>, Schedule.Schedule<[[number, number], number], void, never>>(this: Schedule.Schedule<[number, number], void, never>, ab: (_: Schedule.Schedule<[number, number], void, never>) => Schedule.Schedule<[[number, number], number], void, never>, bc: (_: Schedule.Schedule<[[number, number], number], void, never>) => Schedule.Schedule<[[number, number], number], void, never>): Schedule.Schedule<...> (+21 overloads)
pipe
(
// 为示例限制迭代次数
import Schedule
Schedule
.
const intersect: <number, unknown, never>(that: Schedule.Schedule<number, unknown, never>) => <Out, In, R>(self: Schedule.Schedule<Out, In, R>) => Schedule.Schedule<[Out, number], In, R> (+1 overload)

Combines two schedules, continuing only if both schedules want to continue, using the longer delay.

Details

This function takes two schedules and creates a new schedule that only continues execution if both schedules allow it. The interval between recurrences is determined by the longer delay between the two schedules.

The output of the resulting schedule is a tuple containing the outputs of both schedules. The input type is the intersection of both schedules' input types.

This is useful when coordinating multiple scheduling conditions where execution should proceed only when both schedules permit it.

@seeintersectWith If you need to use a custom merge function.

@since2.0.0

intersect
(
import Schedule
Schedule
.
const recurs: (n: number) => Schedule.Schedule<number>

A schedule that recurs a fixed number of times before terminating.

Details

This schedule will continue executing until it has been stepped n times, after which it will stop. The output of the schedule is the current count of recurrences.

@since2.0.0

recurs
(10)),
import Schedule
Schedule
.
const tapOutput: <void, never, [[number, number], number]>(f: (out: [[number, number], number]) => Effect.Effect<void, never, never>) => <In, R>(self: Schedule.Schedule<[[number, number], number], In, R>) => Schedule.Schedule<[[number, number], number], In, R> (+1 overload)

Returns a new schedule that runs the given effectful function for each output before continuing execution.

Details

This function allows side effects to be performed on each output produced by the schedule. It does not modify the schedule’s behavior but ensures that the provided function f runs after each step.

@since2.0.0

tapOutput
(([
type Out: [number, number]
Out
]) =>
import Console
Console
.
const log: (...args: ReadonlyArray<any>) => Effect.Effect<void>

@since2.0.0

log
(
let i: number
i
=== 11 ? "..." : [new
var Date: DateConstructor
new (value: number | string | Date) => Date (+3 overloads)
Date
(
type Out: [number, number]
Out
[0]), new
var Date: DateConstructor
new (value: number | string | Date) => Date (+3 overloads)
Date
(
type Out: [number, number]
Out
[1])]
)
)
)
),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const fork: <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<Fiber.RuntimeFiber<A, E>, never, R>

Creates a new fiber to run an effect concurrently.

Details

This function takes an effect and forks it into a separate fiber, allowing it to run concurrently without blocking the original effect. The new fiber starts execution immediately after being created, and the fiber object is returned immediately without waiting for the effect to begin. This is useful when you want to run tasks concurrently while continuing other tasks in the parent fiber.

The forked fiber is attached to the parent fiber's scope. This means that when the parent fiber terminates, the child fiber will also be terminated automatically. This feature, known as "auto supervision," ensures that no fibers are left running unintentionally. If you prefer not to have this auto supervision behavior, you can use

forkDaemon

or

forkIn

.

When to Use

Use this function when you need to run an effect concurrently without blocking the current execution flow. For example, you might use it to launch background tasks or concurrent computations. However, working with fibers can be complex, so before using this function directly, you might want to explore higher-level functions like

raceWith

,

zip

, or others that can manage concurrency for you.

Example

import { Effect } from "effect"
const fib = (n: number): Effect.Effect<number> =>
n < 2
? Effect.succeed(n)
: Effect.zipWith(fib(n - 1), fib(n - 2), (a, b) => a + b)
// ┌─── Effect<RuntimeFiber<number, never>, never, never>
// ▼
const fib10Fiber = Effect.fork(fib(10))

@seeforkWithErrorHandler for a version that allows you to handle errors.

@since2.0.0

fork
)
yield*
import TestClock
TestClock
.
const adjust: (durationInput: DurationInput) => Effect.Effect<void>

Accesses a TestClock instance in the context and increments the time by the specified duration, running any actions scheduled for on or before the new time in order.

@since2.0.0

adjust
(
var Infinity: number
Infinity
)
yield*
import Fiber
Fiber
.
const join: <[[number, number], number], never>(self: Fiber.Fiber<[[number, number], number], never>) => Effect.Effect<[[number, number], number], never, never>

Joins the fiber, which suspends the joining fiber until the result of the fiber has been determined. Attempting to join a fiber that has erred will result in a catchable error. Joining an interrupted fiber will result in an "inner interruption" of this fiber, unlike interruption triggered by another fiber, "inner interruption" can be caught and recovered.

@since2.0.0

join
(
const fiber: Fiber.RuntimeFiber<[[number, number], number], never>
fiber
)
}).
Pipeable.pipe<Effect.Effect<void, never, never>, Effect.Effect<void, never, never>, Promise<void>>(this: Effect.Effect<void, never, never>, ab: (_: Effect.Effect<void, never, never>) => Effect.Effect<void, never, never>, bc: (_: Effect.Effect<void, never, never>) => Promise<void>): Promise<void> (+21 overloads)
pipe
(
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const provide: <TestServices, never, never>(layer: Layer<TestServices, never, never>) => <A, E, R>(self: Effect.Effect<A, E, R>) => Effect.Effect<A, E, Exclude<R, TestServices>> (+9 overloads)

Provides necessary dependencies to an effect, removing its environmental requirements.

Details

This function allows you to supply the required environment for an effect. The environment can be provided in the form of one or more Layers, a Context, a Runtime, or a ManagedRuntime. Once the environment is provided, the effect can run without requiring external dependencies.

You can compose layers to create a modular and reusable way of setting up the environment for effects. For example, layers can be used to configure databases, logging services, or any other required dependencies.

Example

import { Context, Effect, Layer } from "effect"
class Database extends Context.Tag("Database")<
Database,
{ readonly query: (sql: string) => Effect.Effect<Array<unknown>> }
>() {}
const DatabaseLive = Layer.succeed(
Database,
{
// Simulate a database query
query: (sql: string) => Effect.log(`Executing query: ${sql}`).pipe(Effect.as([]))
}
)
// ┌─── Effect<unknown[], never, Database>
// ▼
const program = Effect.gen(function*() {
const database = yield* Database
const result = yield* database.query("SELECT * FROM users")
return result
})
// ┌─── Effect<unknown[], never, never>
// ▼
const runnable = Effect.provide(program, DatabaseLive)
Effect.runPromise(runnable).then(console.log)
// Output:
// timestamp=... level=INFO fiber=#0 message="Executing query: SELECT * FROM users"
// []

@seeprovideService for providing a service to an effect.

@since2.0.0

provide
(
import TestContext
TestContext
.
const TestContext: Layer<TestServices, never, never>

@since2.0.0

TestContext
),
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const runPromise: <A, E>(effect: Effect.Effect<A, E, never>, options?: {
readonly signal?: AbortSignal | undefined;
} | undefined) => Promise<A>

Executes an effect and returns the result as a Promise.

Details

This function runs an effect and converts its result into a Promise. If the effect succeeds, the Promise will resolve with the successful result. If the effect fails, the Promise will reject with an error, which includes the failure details of the effect.

The optional options parameter allows you to pass an AbortSignal for cancellation, enabling more fine-grained control over asynchronous tasks.

When to Use

Use this function when you need to execute an effect and work with its result in a promise-based system, such as when integrating with third-party libraries that expect Promise results.

Example (Running a Successful Effect as a Promise)

import { Effect } from "effect"
Effect.runPromise(Effect.succeed(1)).then(console.log)
// Output: 1

Example (Handling a Failing Effect as a Rejected Promise)

import { Effect } from "effect"
Effect.runPromise(Effect.fail("my error")).catch(console.error)
// Output:
// (FiberFailure) Error: my error

@seerunPromiseExit for a version that returns an Exit type instead of rejecting.

@since2.0.0

runPromise
)
}
// 构建一个在每月8日到14日
// 凌晨4:00触发的cron
const
const cron: Cron.Cron
cron
=
import Cron
Cron
.
const unsafeParse: (cron: string, tz?: TimeZone | string) => Cron.Cron

Parses a cron expression into a Cron instance.

Details

This function takes a cron expression as a string and attempts to parse it into a Cron instance. If the expression is valid, the resulting Cron instance will represent the schedule defined by the cron expression.

If the expression is invalid, the function throws a ParseError.

You can optionally provide a time zone (tz) to interpret the cron expression in a specific time zone. If no time zone is provided, the cron expression will use the default time zone.

@example

import { Cron } from "effect"
// At 04:00 on every day-of-month from 8 through 14.
console.log(Cron.unsafeParse("0 4 8-14 * *"))
// Output:
// {
// _id: 'Cron',
// tz: { _id: 'Option', _tag: 'None' },
// seconds: [ 0 ],
// minutes: [ 0 ],
// hours: [ 4 ],
// days: [
// 8, 9, 10, 11,
// 12, 13, 14
// ],
// months: [],
// weekdays: []
// }

@since2.0.0

unsafeParse
("0 0 4 8-14 * *", "UTC")
// 将Cron转换为Schedule
const
const schedule: Schedule.Schedule<[number, number], unknown, never>
schedule
=
import Schedule
Schedule
.
const cron: (cron: Cron.Cron) => Schedule.Schedule<[number, number]> (+1 overload)

Creates a schedule that recurs based on a cron expression.

Details

This schedule automatically executes at intervals defined by a cron expression. It triggers at the beginning of each matched interval and produces timestamps representing the start and end of the cron window.

The cron expression is validated lazily, meaning errors may only be detected when the schedule is executed.

@since2.0.0

cron
(
const cron: Cron.Cron
cron
)
// 定义一个要重复的虚拟操作
const
const action: Effect.Effect<void, never, never>
action
=
import Effect

@since2.0.0

@since2.0.0

@since2.0.0

Effect
.
const void: Effect.Effect<void, never, never>
export void

Represents an effect that does nothing and produces no value.

When to Use

Use this effect when you need to represent an effect that does nothing. This is useful in scenarios where you need to satisfy an effect-based interface or control program flow without performing any operations. For example, it can be used in situations where you want to return an effect from a function but do not need to compute or return any result.

@since2.0.0

void
// 记录调度间隔
const log: <void>(action: Effect.Effect<void, never, never>, schedule: Schedule.Schedule<[number, number], void>) => void
log
(
const action: Effect.Effect<void, never, never>
action
,
const schedule: Schedule.Schedule<[number, number], unknown, never>
schedule
)
/*
输出:
[ 1970-01-08T04:00:00.000Z, 1970-01-08T04:00:01.000Z ]
[ 1970-01-09T04:00:00.000Z, 1970-01-09T04:00:01.000Z ]
[ 1970-01-10T04:00:00.000Z, 1970-01-10T04:00:01.000Z ]
[ 1970-01-11T04:00:00.000Z, 1970-01-11T04:00:01.000Z ]
[ 1970-01-12T04:00:00.000Z, 1970-01-12T04:00:01.000Z ]
[ 1970-01-13T04:00:00.000Z, 1970-01-13T04:00:01.000Z ]
[ 1970-01-14T04:00:00.000Z, 1970-01-14T04:00:01.000Z ]
[ 1970-02-08T04:00:00.000Z, 1970-02-08T04:00:01.000Z ]
[ 1970-02-09T04:00:00.000Z, 1970-02-09T04:00:01.000Z ]
[ 1970-02-10T04:00:00.000Z, 1970-02-10T04:00:01.000Z ]
...
*/