deno.land / x / cockatiel@v3.1.2 / changelog.md
timeout()
in wrap()
(#69)abortOnReturn
to timeouts (#72)wrap()
ed policies in the merged policy (#61)breaking: refactor: create policies as free-floating functions rather than Policy methods
Previously, all policies were created via something like Policy.handleAll().retry(...)
. However, as a result, it was hard for bundlers to tree-shake Cockatiel, since the Policy
class was used and referenced every mechanism provided in this library.
Instead, policies are now created via functions that consume the base Policy
configuration--and that configuration is started as free functions rather than static methods. For example, where you previously wrote:
import { Policy } from 'cockatiel';
Policy.handleAll().retry().attempts(3);
You instead write
import { handleAll, retry } from 'cockatiel';
retry(handleAll, { attempts: 3 );
The full changes are:
Policy.retry()
-> retry(policy, options)
Policy.circuitBreaker(halfOpenAfter, breaker)
-> retry(policy, { halfOpenAfter: number, breaker: IBreaker })
Policy.fallback(valueOrFactory)
-> fallback(policy, valueOrFactory)
Policy.wrap(...)
-> wrap(...)
Policy.timeout(duration, strategy)
-> timeout(duration, strategy)
Policy.bulkhead(limit[, quue])
-> bulkhead(limit[, quue])
Policy.use()
-> usePolicy(policy)
This resolves #50
breaking: refactor: remove confusing Retry builder.
Previously, this package had a builder interface on Policy.retry()...
. However, it was confusing how the different options of the builder interacted in more complex cases. For example, both the retry policy itself and the backoff could have different max attempts.
We simplified it to be a simple options object given in policy
, where the max attempts is also given. For the backoff itself, you pass the underlying backoff generator (or a custom one)
Instead of:
Policy.retry().attempts(2).delay(5)
, you can write retry(policy, { maxAttempts: 2, backoff: new ConstantBackoff(5) })
Policy.retry().delay([100, 200, 300])
, you can write retry(policy, { maxAttempts: 3, backoff: new IterableBackoff(100, 200, 300) })
Policy.retry().exponential(opts)
, you can write retry(policy, { backoff: new ExponentialBackoff(opts) })
Policy.retry().delegate(fn)
, you can write retry(policy, { backoff: new DelegateBackoff(fn) })
This is a little more verbose, but should be more clear to readers, and it also tree-shakes better.
As part of this, the CompositeBackoff
has been removed. This was mostly an implementation detail of the retry builder internally, and can be better implemented as a custom function in a DelegateBackoff
by most consumers.
This resolves #58
fix: TypeScript warnings when using other providers of AbortSignal
.
breaking: refactor: move to using native AbortSignal
over CancellationToken
.
Previously, this package provided its own implementation of cancellation via the CancellationTokenSource
and CancellationToken
. Now, we use the native AbortSignal
which is available in browsers and Node.js since Node 16. To migrate, instead of...
context.cancellationToken
, access context.signal
which is an AbortSignal
,AbortSignal
as the second argument to Policy.execute
, instead of a CancellationToken
,signal.aborted
instead of signal.isCancellationRequested
to check for cancellation,signal.addEventListener("abort", fn)
instead of signal.onCancellationRequested(fn)
to listen for cancellation,new AbortController()
instead of new CancellationTokenSource()
, and ctrl.abort()
and ctrl.signal
instead of ctrl.cancel()
and ctrl.token()
,deriveAbortController(signal)
exported from this package instead of new CancellationTokenSource(parent)
.IDisposable
RetryPolicy.onGiveUp
retry().backoff()
(#34)breaking: reactor: introduce a separate BackoffFactory interface for the first backoff
This only requires changes if you use retry policies in your own code, outside of the Policy.retry()
.
See #30. For some backoff policies, such as delegate and exponential policies, the first backoff was always 0, before next()
was called. This is undesirable, and fixing it involved separating the backoff factory from the backoff itself.
The backoff classes, such as DelegateBackoff
and ExponentialBackoff
, now only have a next()
method. The duration
, which is now a property instead of a method, is only available after the first next()
call.
For example, previously if you did this:
let backoff = new ExponentialBackoff();
while (!succeeded) {
if (!tryAgain()) {
await delay(backoff.duration());
backoff = backoff.next();
}
}
You now need to call next()
before you access duration
:
let backoff = new ExponentialBackoff();
while (!succeeded) {
if (!tryAgain()) {
backoff = backoff.next();
await delay(backoff.duration);
}
}
Note: if you use typescript, you will need another variable for it to understand you. Here's an example of how we use it inside the RetryPolicy.
CancellationToken
to IPolicy.execute
. Add cancellation awareness to all policies; see their specific documentation for more information. (see #25)Policy.circuitBreaker
and unnecessary dashes in jsdoc comments (see #22, #23, #24)FallbackPolicy.onFallback
is replaced with FallbackPolicy.onFailure
. When a failure happens, a fallback will occur.isBrokenCircuitError
, isBulkheadRejectedError
, isIsolatedCircuitError
, isTaskCancelledError
methods to the errors and matching predicate functions.onFailure
and onSuccess
callbacks for monitoring purposes (see #20)onHalfOpen
event to the circuit breaker (see #18)retry.exponential()
requiring an argument when it should have been optional (see #18).dangerouslyUnref
methods for timeouts and retries (#11, thanks to @novemberborn)Timeout.Aggressive
triggering timeouts immediately (#16, thanks to @ekillops)Policy.use()
decoratorretry.exponential()
Initial Release
Version Info