deno.land / x / cockatiel@v3.1.2 / src / TimeoutPolicy.ts

TimeoutPolicy.ts
نووسراو ببینە
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import { deriveAbortController } from './common/abort';import { Event, EventEmitter, onAbort } from './common/Event';import { ExecuteWrapper, returnOrThrow } from './common/Executor';import { TaskCancelledError } from './errors/TaskCancelledError';import { IPolicy } from './Policy';
export enum TimeoutStrategy { /** * Cooperative timeouts will simply revoke the inner cancellation token, * assuming the caller handles cancellation and throws or returns appropriately. */ Cooperative = 'optimistic',
/** * Aggressive cancellation immediately throws */ Aggressive = 'aggressive',}
export interface ICancellationContext { signal: AbortSignal;}
export interface ITimeoutOptions { /** Strategy for timeouts, "Cooperative", or "Accessive" */ strategy: TimeoutStrategy; /** * Whether the AbortSignal should be aborted when the * function returns. Defaults to true. */ abortOnReturn?: boolean;}
export class TimeoutPolicy implements IPolicy<ICancellationContext> { declare readonly _altReturn: never;
private readonly timeoutEmitter = new EventEmitter<void>();
/** * @inheritdoc */ public readonly onTimeout = this.timeoutEmitter.addListener;
/** * @inheritdoc */ public readonly onFailure = this.executor.onFailure;
/** * @inheritdoc */ public readonly onSuccess = this.executor.onSuccess;
constructor( private readonly duration: number, private readonly options: ITimeoutOptions, private readonly executor = new ExecuteWrapper(), private readonly unref = false, ) {}
/** * When timing out, a referenced timer is created. This means the Node.js * event loop is kept active while we're waiting for the timeout, as long as * the function hasn't returned. Calling this method on the timeout builder * will unreference the timer, allowing the process to exit even if a * timeout might still be happening. */ public dangerouslyUnref() { const t = new TimeoutPolicy(this.duration, this.options, this.executor, true); return t; }
/** * Executes the given function. * @param fn Function to execute. Takes in a nested cancellation token. * @throws a {@link TaskCancelledError} if a timeout occurs */ public async execute<T>( fn: (context: ICancellationContext, signal: AbortSignal) => PromiseLike<T> | T, signal?: AbortSignal, ): Promise<T> { const aborter = deriveAbortController(signal); const timer = setTimeout(() => aborter.abort(), this.duration); if (this.unref) { timer.unref(); }
const context = { signal: aborter.signal };
const onceAborted = onAbort(aborter.signal); const onCancelledListener = onceAborted(() => this.timeoutEmitter.emit());
try { if (this.options.strategy === TimeoutStrategy.Cooperative) { return returnOrThrow(await this.executor.invoke(fn, context, aborter.signal)); }
return await this.executor .invoke(async () => Promise.race<T>([ Promise.resolve(fn(context, aborter.signal)), Event.toPromise(onceAborted).then(() => { throw new TaskCancelledError(`Operation timed out after ${this.duration}ms`); }), ]), ) .then(returnOrThrow); } finally { onCancelledListener.dispose(); if (this.options.abortOnReturn !== false) { aborter.abort(); } clearTimeout(timer); } }}
cockatiel

Version Info

Tagged at
5 months ago