(poolName: string, query: string)
| 67 | const recentWarnings = new Map<string, number>() |
| 68 | |
| 69 | function report(poolName: string, query: string): void { |
| 70 | const mode = resolveMode() |
| 71 | if (mode === 'off') return |
| 72 | |
| 73 | const queryPreview = query.replace(/\s+/g, ' ').slice(0, 160) |
| 74 | const message = |
| 75 | `Query on the global "${poolName}" pool issued inside a transaction callback. ` + |
| 76 | 'The transaction already holds a pooled connection, so this checks out a second one ' + |
| 77 | 'and can deadlock the pool at saturation. Pass the tx handle to the query, hoist the ' + |
| 78 | 'work above the transaction, or wrap deliberate fire-and-forget global-pool work in ' + |
| 79 | 'runOutsideTransactionContext().' |
| 80 | |
| 81 | if (mode === 'throw') { |
| 82 | throw new Error(`${message} Query: ${queryPreview}`) |
| 83 | } |
| 84 | |
| 85 | const now = Date.now() |
| 86 | const lastLogged = recentWarnings.get(queryPreview) |
| 87 | if (lastLogged !== undefined && now - lastLogged < WARN_DEDUPE_WINDOW_MS) return |
| 88 | if (recentWarnings.size >= WARN_DEDUPE_MAX_KEYS) { |
| 89 | for (const [key, loggedAt] of recentWarnings) { |
| 90 | if (now - loggedAt >= WARN_DEDUPE_WINDOW_MS) recentWarnings.delete(key) |
| 91 | } |
| 92 | if (recentWarnings.size >= WARN_DEDUPE_MAX_KEYS) recentWarnings.clear() |
| 93 | } |
| 94 | recentWarnings.set(queryPreview, now) |
| 95 | logger.error(message, { poolName, queryPreview, stack: new Error().stack }) |
| 96 | } |
| 97 | |
| 98 | /** |
| 99 | * Minimal structural surface of a postgres-js root client needed by the |
no test coverage detected