// ets_tracing: off import type { HasClock } from "../Clock/index.js" import * as E from "../Either/index.js" import { identity, pipe } from "../Function/index.js" import type { Driver, Schedule } from "../Schedule/index.js" import * as schedule from "../Schedule/index.js" import * as catchAll from "./catchAll.js" import * as core from "./core.js" import type { Effect } from "./effect.js" import * as fail from "./fail.js" import * as foldM from "./foldM.js" import * as map from "./map.js" import * as orDie from "./orDie.js" function loop( self: Effect, orElse: (e: E, o: O) => Effect, driver: Driver ): Effect> { return pipe( self, map.map((a) => E.right(a)), catchAll.catchAll((e) => pipe( driver.next(e), foldM.foldM( () => pipe( driver.last, orDie.orDie, core.chain((o) => pipe( orElse(e, o), map.map((a) => E.left(a)) ) ) ), () => loop(self, orElse, driver) ) ) ) ) } /** * Returns an effect that retries this effect with the specified schedule when it fails, until * the schedule is done, then both the value produced by the schedule together with the last * error are passed to the specified recovery function. */ export function retryOrElseEither_( self: Effect, policy: Schedule, orElse: (e: E, o: O) => Effect, __trace?: string ): Effect> { return pipe( policy, schedule.driver, core.chain((a) => loop(self, orElse, a), __trace) ) } /** * Returns an effect that retries this effect with the specified schedule when it fails, until * the schedule is done, then both the value produced by the schedule together with the last * error are passed to the specified recovery function. * * @ets_data_first retryOrElseEither_ */ export function retryOrElseEither( policy: Schedule, orElse: (e: E, o: O) => Effect, __trace?: string ) { return (self: Effect) => retryOrElseEither_(self, policy, orElse, __trace) } /** * Retries with the specified schedule, until it fails, and then both the * value produced by the schedule together with the last error are passed to * the recovery function. */ export function retryOrElse_( self: Effect, policy: Schedule, orElse: (e: E, o: O) => Effect, __trace?: string ): Effect { return map.map_( retryOrElseEither_(self, policy, orElse, __trace), E.fold(identity, identity) ) } /** * Retries with the specified schedule, until it fails, and then both the * value produced by the schedule together with the last error are passed to * the recovery function. * * @ets_data_first retryOrElse_ */ export function retryOrElse( policy: Schedule, orElse: (e: E, o: O) => Effect, __trace?: string ) { return (self: Effect) => retryOrElse_(self, policy, orElse, __trace) } /** * Retries with the specified retry policy. * Retries are done following the failure of the original `io` (up to a fixed maximum with * `once` or `recurs` for example), so that that `io.retry(Schedule.once)` means * "execute `io` and in case of failure, try again once". */ export function retry_( self: Effect, policy: Schedule, __trace?: string ): Effect { return retryOrElse_(self, policy, (e, _) => fail.fail(e), __trace) } /** * Retries with the specified retry policy. * Retries are done following the failure of the original `io` (up to a fixed maximum with * `once` or `recurs` for example), so that that `io.retry(Schedule.once)` means * "execute `io` and in case of failure, try again once". * * @ets_data_first retry_ */ export function retry(policy: Schedule, __trace?: string) { return (self: Effect): Effect => retry_(self, policy, __trace) }