Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
File size: 4,112 Bytes
6215321 |
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 |
export enum PromiseResponseType {
Resolved,
Rejected,
Expired
}
export type PromiseResponse<T> =
{
status: PromiseResponseType.Resolved
value: T
error: undefined
} |
{
status: PromiseResponseType.Rejected
value: undefined
error: Error
} |
{
status: PromiseResponseType.Expired
value: undefined
error: Error
}
/**
* This function waits for an array of promises to finish
*
* Behavior:
*
* As soon as any of the promises resolve,
* this triggers an internal countdown (based on maxRunTimeAfterFirstResolveInMs)
* after which the function will stop everything, and return the promises results.
* Promises that finish after countdownAfterFirstResolveInMs will be ignored and their result discarded.
*
* The result is an array matching the input number of promises, but with different status based on what happened:
*
* Promises that resolved will be of type `{ status: PromiseResponseType.Resolved, value: ...... }`.
* Promises that failed will be of type `{ status: PromiseResponseType.Rejected, error: ...... }`.
* Promises that failed will be of type `{ status: PromiseResponseType.Expired, error: ...... }`.
*
* Note that it is possible that no promises resolves at all,
* which is why we also have a global expiration timeout (based on maxTotalRunTimeInMs) with more priority,
* that will also stop the function and return the promises results (they will also have the expired status)
*
* Note that maxTotalRunTimeInMs is reached, countdownAfterFirstResolveInMs becomes irrelevant,
* so all promises that finish after maxTotalRunTimeInMs will be ignored and their result discarded.
*/
export async function waitPromisesUntil<T>(
promises: Promise<T>[],
countdownAfterFirstResolveInMs: number = 1000,
maxTotalRunTimeInMs: number = 10000
): Promise<PromiseResponse<T>[]> {
// This will store the result for each promise as it finishes or the operation is terminated.
const results: PromiseResponse<T>[] = Array(promises.length).fill(undefined);
/*{
status: "expired",
error: new Error("Promise expired")
});
*/
// Timer to handle maxTotalRunTimeInMs
let globalTimeoutHandler: any;
// Timer to handle countdownAfterFirstResolveInMs
let firstResolveCountdownHandler: any;
// Helper function to handle promise resolution
const handleResolved = (index: number, value: T) => {
if (!results[index]) { // If result isn't yet set
results[index] = { status: PromiseResponseType.Resolved, value, error: undefined };
}
if (!firstResolveCountdownHandler) {
// Start countdown after the first resolve
firstResolveCountdownHandler = setTimeout(() => {
finalizePromises(); // Stop accepting results after the countdown
}, countdownAfterFirstResolveInMs);
}
};
// Helper function to handle promise rejection
const handleRejected = (index: number, error: any) => {
if (!results[index]) {
results[index] = { status: PromiseResponseType.Rejected, error, value: undefined };
}
};
// Early finalization function to handle both timeouts
const finalizePromises = () => {
clearTimeout(globalTimeoutHandler);
clearTimeout(firstResolveCountdownHandler);
for (let i = 0; i < promises.length; i++) {
if (!results[i]) { // Promises that have not been settled by either handler
results[i] = { status: PromiseResponseType.Expired, error: new Error('Promise expired'), value: undefined };
}
}
};
// Wrap each promise with resolution and rejection handlers
const watchedPromises = promises.map((promise, index) =>
promise.then(
value => handleResolved(index, value),
error => handleRejected(index, error)
)
);
// Set the global timeout
globalTimeoutHandler = setTimeout(() => {
finalizePromises();
}, maxTotalRunTimeInMs);
// Await all wrapped promises
await Promise.all(watchedPromises.map(p => p.catch(() => {}))); // Catch errors to prevent early exits
finalizePromises(); // Finalize to ensure all promises not settled are marked expired
return results;
} |