/** Errors of the infrastructure itself: waiting is the cure, not skipping. */ const TRANSIENT_NAMES = /^(Mongo(Network|NetworkTimeout|ServerSelection|NotConnected|TopologyClosed|PoolCleared)Error|MaxRetriesPerRequestError)$/; const TRANSIENT_CODES = new Set([ 'ECONNREFUSED', 'ECONNRESET', 'ETIMEDOUT', 'EPIPE', 'EHOSTUNREACH', 'ENETUNREACH', 'ENOTFOUND', 'EAI_AGAIN', ]); const TRANSIENT_MESSAGES = /connection (is )?closed|connection refused|timed out|getaddrinfo|socket hang up/i; /** * Whether an error comes from a database or the network being down (and * will go away by itself) rather than from the event or the code that * handles it. Follows `cause`, as drivers wrap the original error. */ export function isTransientError(error: unknown): boolean { for (let current = error, depth = 0; current && depth < 5; depth++) { const e = current as { name?: string; code?: string; message?: string; cause?: unknown; }; if (e.name && TRANSIENT_NAMES.test(e.name)) return true; if (e.code && TRANSIENT_CODES.has(e.code)) return true; if (e.message && TRANSIENT_MESSAGES.test(e.message)) return true; current = e.cause; } return false; }