"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.retryTransientEsErrors = void 0;
var _elasticsearch = require("@elastic/elasticsearch");
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0; you may not use this file except in compliance with the Elastic License
 * 2.0.
 */

const MAX_ATTEMPTS = 3;
const retryResponseStatuses = [503,
// ServiceUnavailable
408,
// RequestTimeout
410 // Gone
];

const isRetryableError = e => e instanceof _elasticsearch.errors.NoLivingConnectionsError || e instanceof _elasticsearch.errors.ConnectionError || e instanceof _elasticsearch.errors.TimeoutError || e instanceof _elasticsearch.errors.ResponseError && retryResponseStatuses.includes(e === null || e === void 0 ? void 0 : e.statusCode);
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const retryTransientEsErrors = async (esCall, {
  logger,
  attempt = 0
}) => {
  try {
    return await esCall();
  } catch (e) {
    if (attempt < MAX_ATTEMPTS && isRetryableError(e)) {
      const retryCount = attempt + 1;
      const retryDelaySec = Math.min(Math.pow(2, retryCount), 30); // 2s, 4s, 8s, 16s, 30s, 30s, 30s...

      logger.warn(`Retrying Elasticsearch operation after [${retryDelaySec}s] due to error: ${e.toString()} ${e.stack}`);

      // delay with some randomness
      await delay(retryDelaySec * 1000 * Math.random());
      return retryTransientEsErrors(esCall, {
        logger,
        attempt: retryCount
      });
    }
    throw e;
  }
};
exports.retryTransientEsErrors = retryTransientEsErrors;