重复执行
探索 Effect 中的重复执行:按照指定策略多次执行同一个 Effect,并控制重复次数、失败与条件。
在软件开发中,重复执行 Effect 是一项常见需求。它允许我们按照特定的重复策略多次执行同一个 Effect。
repeat
Effect.repeat 函数返回一个新的 Effect,它会按照指定的 Schedule 重复给定的 Effect,或者重复到第一次失败为止。
计划中的重复次数是在初次执行之外额外增加的,因此
Effect.repeat(action, Schedule.duration(Duration.zero)) 会先执行一次 action,
如果成功,再额外重复一次。
示例(重复一个成功的 Effect)
import { Effect, Schedule, Console } from "effect"
// Define an effect that logs a message to the console
const action = Console.log("success")
// Define a schedule that repeats the action 2 more times with a delay
const policy = Schedule.addDelay(Schedule.recurs(2), () =>
Effect.succeed("100 millis"),
)
// Repeat the action according to the schedule
const program = Effect.repeat(action, policy)
// Run the program and log the number of repetitions
const repetitions = await Effect.runPromise(program)
console.log(`repetitions: ${repetitions}`)
/*
Output:
success
success
success
repetitions: 2
*/
repetitions // => 2
示例(处理重复中的失败)
import { Effect, Schedule, Exit } from "effect"
let count = 0
// Define an async effect that simulates an action with potential failure
const action = Effect.callback<string, string>((resume) => {
if (count > 1) {
console.log("failure")
resume(Effect.fail("Uh oh!"))
} else {
count++
console.log("success")
resume(Effect.succeed("yay!"))
}
})
// Define a schedule that repeats the action 2 more times with a delay
const policy = Schedule.addDelay(Schedule.recurs(2), () =>
Effect.succeed("100 millis"),
)
// Repeat the action according to the schedule
const program = Effect.repeat(action, policy)
// Run the program and observe the result on failure
const exit = await Effect.runPromiseExit(program)
console.log(exit)
/*
Output:
success
success
failure
*/
exit // => Exit.fail("Uh oh!")
跳过首次执行
如果你想避免首次执行,只按照 Schedule 运行该动作,可以使用 Effect.schedule。这会让 Effect 跳过最初的运行,直接遵循定义好的重复策略。
示例(跳过首次执行)
import { Effect, Schedule, Console } from "effect"
const action = Console.log("success")
const policy = Schedule.addDelay(Schedule.recurs(2), () =>
Effect.succeed("100 millis"),
)
const program = Effect.schedule(action, policy)
const repetitions = await Effect.runPromise(program)
console.log(`repetitions: ${repetitions}`)
/*
Output:
success
success
repetitions: 2
*/
repetitions // => 2
repeatN
Effect.repeat 函数返回一个新的 Effect,它会将指定的 Effect 重复给定的次数,或者重复到第一次失败为止。这些重复次数是在初次执行之外额外增加的,因此 Effect.repeat(action, { times: 1 }) 会先执行一次 action,如果成功,再额外重复一次。
示例(多次重复一个动作)
import { Effect, Console } from "effect"
const action = Console.log("success")
// Repeat the action 2 additional times after the first execution
const program = Effect.repeat(action, { times: 2 })
const result = await Effect.runPromise(program)
/*
Output:
success
success
success
*/
result // => undefined
repeatOrElse
repeatOrElse 函数返回一个新的 Effect,它会按照给定的 Schedule 重复指定的 Effect,或者重复到第一次失败为止。
发生失败时,失败值和 Schedule 的输出会被传给指定的处理函数。
计划中的重复次数是在初次执行之外额外增加的,因此 Effect.repeat(action, Schedule.duration(Duration.zero)) 会先执行一次 action,如果成功,再额外重复一次。
示例(处理重复过程中的失败)
import { Effect, Schedule } from "effect"
let count = 0
// Define an async effect that simulates an action with possible failures
const action = Effect.callback<string, string>((resume) => {
if (count > 1) {
console.log("failure")
resume(Effect.fail("Uh oh!"))
} else {
count++
console.log("success")
resume(Effect.succeed("yay!"))
}
})
// Define a schedule that repeats up to 2 times
// with a 100ms delay between attempts
const policy = Schedule.addDelay(Schedule.recurs(2), () =>
Effect.succeed("100 millis"),
)
// Provide a handler to run when failure occurs after the retries
const program = Effect.repeatOrElse(action, policy, () =>
Effect.sync(() => {
console.log("orElse")
return count - 1
}),
)
const repetitions = await Effect.runPromise(program)
console.log(`repetitions: ${repetitions}`)
/*
Output:
success
success
failure
orElse
repetitions: 1
*/
repetitions // => 1
基于条件重复
你可以使用 while 或 until 选项,通过条件来控制一个 Effect 的重复,从而根据运行时的结果进行动态控制。
示例(重复直到满足某个条件)
import { Effect } from "effect"
let count = 0
// Define an effect that simulates varying outcomes on each invocation
const action = Effect.sync(() => {
console.log(`Action called ${++count} time(s)`)
return count
})
// Repeat the action until the count reaches 3
const program = Effect.repeat(action, { until: (n) => n === 3 })
const result = await Effect.runPromise(program)
/*
Output:
Action called 1 time(s)
Action called 2 time(s)
Action called 3 time(s)
*/
result // => 3
如果你需要基于错误的发生而不是成功的结果来设置条件,可以使用 Effect.retry。