HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux ip-172-31-4-197 6.8.0-1036-aws #38~22.04.1-Ubuntu SMP Fri Aug 22 15:44:33 UTC 2025 x86_64
User: ubuntu (1000)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/api-storage/node_modules/minio/src/internal/request.ts
import type * as http from 'node:http'
import type * as https from 'node:https'
import type * as stream from 'node:stream'
import { pipeline } from 'node:stream'
import { promisify } from 'node:util'

import type { Transport } from './type.ts'

const pipelineAsync = promisify(pipeline)

export async function request(
  transport: Transport,
  opt: https.RequestOptions,
  body: Buffer | string | stream.Readable | null = null,
): Promise<http.IncomingMessage> {
  return new Promise<http.IncomingMessage>((resolve, reject) => {
    const requestObj = transport.request(opt, (response) => {
      resolve(response)
    })

    requestObj.on('error', reject)

    if (!body || Buffer.isBuffer(body) || typeof body === 'string') {
      requestObj.end(body)
    } else {
      pipelineAsync(body, requestObj).catch(reject)
    }
  })
}

const MAX_RETRIES = 10
const EXP_BACK_OFF_BASE_DELAY = 1000 // Base delay for exponential backoff
const ADDITIONAL_DELAY_FACTOR = 1.0 // to avoid synchronized retries

// Retryable error codes for HTTP ( ref: minio-go)
export const retryHttpCodes: Record<string, boolean> = {
  408: true,
  429: true,
  499: true,
  500: true,
  502: true,
  503: true,
  504: true,
  520: true,
}

const isHttpRetryable = (httpResCode: number) => {
  return retryHttpCodes[httpResCode] !== undefined
}

const sleep = (ms: number) => {
  return new Promise((resolve) => setTimeout(resolve, ms))
}

const getExpBackOffDelay = (retryCount: number) => {
  const backOffBy = EXP_BACK_OFF_BASE_DELAY * 2 ** retryCount
  const additionalDelay = Math.random() * backOffBy * ADDITIONAL_DELAY_FACTOR
  return backOffBy + additionalDelay
}

export async function requestWithRetry(
  transport: Transport,
  opt: https.RequestOptions,
  body: Buffer | string | stream.Readable | null = null,
  maxRetries: number = MAX_RETRIES,
): Promise<http.IncomingMessage> {
  let attempt = 0
  let isRetryable = false
  while (attempt <= maxRetries) {
    try {
      const response = await request(transport, opt, body)
      // Check if the HTTP status code is retryable
      if (isHttpRetryable(response.statusCode as number)) {
        isRetryable = true
        throw new Error(`Retryable HTTP status: ${response.statusCode}`) // trigger retry attempt with calculated delay
      }

      return response // Success, return the raw response
    } catch (err) {
      if (isRetryable) {
        attempt++
        isRetryable = false

        if (attempt > maxRetries) {
          throw new Error(`Request failed after ${maxRetries} retries: ${err}`)
        }
        const delay = getExpBackOffDelay(attempt)
        // eslint-disable-next-line no-console
        console.warn(
          `${new Date().toLocaleString()} Retrying request (attempt ${attempt}/${maxRetries}) after ${delay}ms due to: ${err}`,
        )
        await sleep(delay)
      } else {
        throw err // re-throw if any request, syntax errors
      }
    }
  }

  throw new Error(`${MAX_RETRIES} Retries exhausted, request failed.`)
}