This is an automated email from the ASF dual-hosted git repository.

CoverRyan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/daffodil-vscode.git


The following commit(s) were added to refs/heads/main by this push:
     new ad6dfce2 add fetch retry logic
ad6dfce2 is described below

commit ad6dfce2480671249a37b735baab2a10f9db743e
Author: CoverRyan <[email protected]>
AuthorDate: Tue Jun 23 00:56:07 2026 -0400

    add fetch retry logic
---
 src/daffodilDebugger/daffodilJars.ts | 10 ++++-----
 src/utils.ts                         | 41 +++++++++++++++++++++++++++++++-----
 2 files changed, 40 insertions(+), 11 deletions(-)

diff --git a/src/daffodilDebugger/daffodilJars.ts 
b/src/daffodilDebugger/daffodilJars.ts
index dcef2419..e6cee07e 100644
--- a/src/daffodilDebugger/daffodilJars.ts
+++ b/src/daffodilDebugger/daffodilJars.ts
@@ -19,7 +19,7 @@ import * as path from 'path'
 import * as fs from 'fs'
 import * as vscode from 'vscode'
 import { outputChannel } from '../adapter/activateDaffodilDebug'
-import { downloadAndExtract } from '../utils'
+import { downloadAndExtract, fetchRetry } from '../utils'
 import { parseStringPromise } from 'xml2js'
 
 /**
@@ -69,11 +69,9 @@ export async function checkIfDaffodilJarsNeeded(
 async function getValidDaffodilVersions(): Promise<string[]> {
   const url = 'https://daffodil.apache.org/doap.rdf'
 
-  const resp = await fetch(url)
-  if (!resp.ok) {
-    throw new Error(
-      `Failed to fetch DOAP RDF: ${resp.status} ${resp.statusText}`
-    )
+  const resp = await fetchRetry(url)
+  if (!resp) {
+    throw new Error(`Failed to fetch DOAP RDF ${url}`)
   }
 
   const xmlText = await resp.text()
diff --git a/src/utils.ts b/src/utils.ts
index 1626a7b0..ca66f66d 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -508,6 +508,39 @@ export const displayModalError = async (
       vscode.window.showErrorMessage(message, { modal: false })
     )
 
+/**
+ * Make HTTP request with retries and exponential backoff
+ *
+ * @param url The url to fetch
+ * @param options The options for the fetch
+ * @param retries Max number of retries
+ * @param delay Initial delay in ms
+ * @returns Response object
+ */
+export async function fetchRetry(
+  url,
+  options = {},
+  retries = 5,
+  delay = 4000
+): Promise<Response | undefined> {
+  let backoff = delay
+  for (let i = 1; i <= retries; i++) {
+    const res = await fetch(url, options)
+    if (!res.ok || !res.body) {
+      if (i === retries) {
+        throw new Error(
+          `Failed request to ${url}: ${res.status} ${res.statusText}`
+        )
+      } else {
+        await new Promise((r) => setTimeout(r, backoff))
+        backoff = backoff * 2
+      }
+    } else {
+      return res
+    }
+  }
+}
+
 /**
  * Download and extract a files with a progress bar
  *
@@ -529,11 +562,9 @@ export async function downloadAndExtract(
     async (progress) => {
       progress.report({ increment: 0, message: 'Starting download...' })
 
-      const res = await fetch(url)
-      if (!res.ok || !res.body) {
-        throw new Error(
-          `Failed to download ${url}: ${res.status} ${res.statusText}`
-        )
+      const res = await fetchRetry(url)
+      if (!res) {
+        throw new Error(`Failed to download ${url}`)
       }
 
       const totalBytes = Number(res.headers.get('content-length')) || 0

Reply via email to