Snowflake returns 202 while still executing and 200 on completion (async statement-handle semantics).
(input: PollInput)
| 333 | |
| 334 | /** Snowflake returns 202 while still executing and 200 on completion (async statement-handle semantics). */ |
| 335 | async function pollStatement(input: PollInput): Promise<void> { |
| 336 | const url = `https://${input.account}.snowflakecomputing.com/api/v2/statements/${encodeURIComponent(input.handle)}` |
| 337 | const deadline = Date.now() + POLL_DEADLINE_MS |
| 338 | let interval = POLL_INITIAL_INTERVAL_MS |
| 339 | let skipIntervalSleep = true |
| 340 | let retryAttempt = 0 |
| 341 | while (Date.now() < deadline) { |
| 342 | if (input.signal.aborted) throw input.signal.reason ?? new Error('Aborted') |
| 343 | if (!skipIntervalSleep) { |
| 344 | await sleepUntilAborted(interval, input.signal) |
| 345 | } |
| 346 | skipIntervalSleep = false |
| 347 | const jwt = await input.getJwt() |
| 348 | const perAttempt = AbortSignal.any([input.signal, AbortSignal.timeout(PER_ATTEMPT_TIMEOUT_MS)]) |
| 349 | let response: Response |
| 350 | try { |
| 351 | response = await fetch(url, { |
| 352 | headers: { |
| 353 | Authorization: `Bearer ${jwt}`, |
| 354 | Accept: 'application/json', |
| 355 | 'X-Snowflake-Authorization-Token-Type': 'KEYPAIR_JWT', |
| 356 | }, |
| 357 | signal: perAttempt, |
| 358 | }) |
| 359 | } catch (error) { |
| 360 | if (input.signal.aborted) throw error |
| 361 | retryAttempt++ |
| 362 | if (retryAttempt > POLL_MAX_CONSECUTIVE_RETRIES) throw error |
| 363 | const delay = backoffWithJitter(retryAttempt, null, { |
| 364 | baseMs: EXECUTE_RETRY_BASE_DELAY_MS, |
| 365 | maxMs: EXECUTE_RETRY_MAX_DELAY_MS, |
| 366 | }) |
| 367 | logger.warn('Snowflake poll request failed, retrying', { |
| 368 | attempt: retryAttempt, |
| 369 | delayMs: delay, |
| 370 | error: toError(error).message, |
| 371 | }) |
| 372 | await sleepUntilAborted(delay, input.signal) |
| 373 | skipIntervalSleep = true |
| 374 | continue |
| 375 | } |
| 376 | if (response.status === 202) { |
| 377 | /** Drain the body so undici can return the socket to the keep-alive pool between polls. */ |
| 378 | await response.text().catch(() => '') |
| 379 | retryAttempt = 0 |
| 380 | interval = Math.min(interval * 2, POLL_MAX_INTERVAL_MS) |
| 381 | continue |
| 382 | } |
| 383 | if (isRetryableStatus(response.status)) { |
| 384 | retryAttempt++ |
| 385 | if (retryAttempt > POLL_MAX_CONSECUTIVE_RETRIES) { |
| 386 | /** Drain the body so undici can return the socket to the keep-alive pool. */ |
| 387 | const text = await response.text().catch(() => '') |
| 388 | throw new Error( |
| 389 | `Snowflake poll failed after ${POLL_MAX_CONSECUTIVE_RETRIES} consecutive retries (HTTP ${response.status}): ${text}` |
| 390 | ) |
| 391 | } |
| 392 | const retryAfterMs = parseRetryAfter(response.headers.get('Retry-After')) |
no test coverage detected