const require_constants = require("../constants.cjs");
const require_errors = require("../errors.cjs");
const require_config = require("./utils/config.cjs");
const require_index = require("./utils/index.cjs");
const require_timeout = require("./timeout.cjs");
const DEFAULT_STATUS_NO_RETRY = [
	400,
	401,
	402,
	403,
	404,
	405,
	406,
	407,
	409
];
const DEFAULT_RETRY_ON_HANDLER = (error) => {
	if (error.message.startsWith("Cancel") || error.message.startsWith("AbortError") || error.name === "AbortError") return false;
	if (error.name === "GraphValueError") return false;
	if (error?.code === "ECONNABORTED") return false;
	const status = error?.response?.status ?? error?.status;
	if (status && DEFAULT_STATUS_NO_RETRY.includes(+status)) return false;
	if (error?.error?.code === "insufficient_quota") return false;
	return true;
};
async function _runWithRetry(pregelTask, retryPolicy, configurable, signal) {
	const resolvedRetryPolicy = pregelTask.retry_policy ?? retryPolicy;
	let attempts = 0;
	let error;
	let result;
	let config = pregelTask.config ?? {};
	if (configurable) config = require_index.patchConfigurable(config, configurable);
	config = {
		...config,
		signal
	};
	const firstAttemptTime = Date.now();
	if (config.executionInfo != null) config.executionInfo = {
		...config.executionInfo,
		nodeFirstAttemptTime: firstAttemptTime
	};
	while (true) {
		if (signal?.aborted) break;
		pregelTask.writes.splice(0, pregelTask.writes.length);
		error = void 0;
		try {
			if (pregelTask.timeout !== void 0) result = await require_timeout.runAttemptWithTimeout(pregelTask, config, pregelTask.timeout, (scopedConfig) => pregelTask.proc.invoke(pregelTask.input, scopedConfig));
			else result = await pregelTask.proc.invoke(pregelTask.input, config);
			break;
		} catch (e) {
			error = e;
			error.pregelTaskId = pregelTask.id;
			if (require_errors.isParentCommand(error)) {
				const ns = config?.configurable?.checkpoint_ns;
				const cmd = error.command;
				if (cmd.graph === ns) {
					for (const writer of pregelTask.writers) await writer.invoke(cmd, config);
					error = void 0;
					break;
				} else if (cmd.graph === require_constants.Command.PARENT) {
					const parentNs = require_config.getParentCheckpointNamespace(ns);
					error.command = new require_constants.Command({
						...error.command,
						graph: parentNs
					});
				}
			}
			if (require_errors.isGraphBubbleUp(error)) break;
			if (resolvedRetryPolicy === void 0) break;
			attempts += 1;
			if (attempts >= (resolvedRetryPolicy.maxAttempts ?? 3)) break;
			if (!(resolvedRetryPolicy.retryOn ?? DEFAULT_RETRY_ON_HANDLER)(error)) break;
			const initialInterval = resolvedRetryPolicy.initialInterval ?? 500;
			const interval = Math.min(resolvedRetryPolicy.maxInterval ?? 128e3, initialInterval * (resolvedRetryPolicy.backoffFactor ?? 2) ** (attempts - 1));
			const sleepMs = resolvedRetryPolicy.jitter ?? true ? interval + Math.random() * 1e3 : interval;
			await new Promise((resolve) => setTimeout(resolve, sleepMs));
			const errorName = error.name ?? error.constructor.unminifiable_name ?? error.constructor.name;
			if (resolvedRetryPolicy?.logWarning ?? true) console.log(`Retrying task "${String(pregelTask.name)}" after ${sleepMs.toFixed(2)}ms (attempt ${attempts}) after ${errorName}: ${error}`);
			config = require_index.patchConfigurable(config, { [require_constants.CONFIG_KEY_RESUMING]: true });
			if (config.executionInfo != null) config.executionInfo = {
				...config.executionInfo,
				nodeAttempt: attempts + 1,
				nodeFirstAttemptTime: firstAttemptTime
			};
		}
	}
	return {
		task: pregelTask,
		result,
		error,
		signalAborted: signal?.aborted
	};
}
//#endregion
exports._runWithRetry = _runWithRetry;

//# sourceMappingURL=retry.cjs.map