Files
Compass/common/src/util/promise.ts
Martin Braquet ba9b3cfb06 Add pretty formatting (#29)
* Test

* Add pretty formatting

* Fix Tests

* Fix Tests

* Fix Tests

* Fix

* Add pretty formatting fix

* Fix

* Test

* Fix tests

* Clean typeckech

* Add prettier check

* Fix api tsconfig

* Fix api tsconfig

* Fix tsconfig

* Fix

* Fix

* Prettier
2026-02-20 17:32:27 +01:00

81 lines
2.1 KiB
TypeScript

export type RetryPolicy = {
initialBackoffSec: number
retries: number
}
export const delay = (ms: number) => {
return new Promise<void>((resolve) => setTimeout(() => resolve(), ms))
}
export async function withRetries<T>(q: PromiseLike<T>, policy?: RetryPolicy) {
let err: Error | undefined
let delaySec = policy?.initialBackoffSec ?? 5
const maxRetries = policy?.retries ?? 5
for (let i = 0; i < maxRetries; i++) {
try {
return await q
} catch (e) {
err = e as Error
if (i < maxRetries) {
console.debug(`Error: ${err.message} - Retrying in ${delaySec}s.`)
await delay(delaySec * 1000)
delaySec *= 2
}
}
}
throw err
}
export const mapAsyncChunked = async <T, U>(
items: T[],
f: (item: T, index: number) => Promise<U>,
chunkSize = 100,
) => {
const results: U[] = []
for (let i = 0; i < items.length; i += chunkSize) {
const chunk = items.slice(i, i + chunkSize)
const chunkResults = await Promise.all(chunk.map((item, index) => f(item, i + index)))
results.push(...chunkResults)
}
return results
}
export const mapAsync = <T, U>(
items: T[],
f: (item: T, index: number) => Promise<U>,
maxConcurrentRequests = 100,
) => {
let index = 0
let currRequests = 0
const results: U[] = []
// The following is a hack to fix a Node bug where the process exits before
// the promise is resolved.
// eslint-disable-next-line @typescript-eslint/no-empty-function
const intervalId = setInterval(() => {}, 10000)
return new Promise((resolve: (results: U[]) => void, reject) => {
const doWork = () => {
while (index < items.length && currRequests < maxConcurrentRequests) {
const itemIndex = index
f(items[itemIndex], itemIndex)
.then((data) => {
results[itemIndex] = data
currRequests--
if (index === items.length && currRequests === 0) resolve(results)
else doWork()
})
.catch(reject)
index++
currRequests++
}
}
if (items.length === 0) resolve([])
else doWork()
}).finally(() => clearInterval(intervalId))
}