@@ -55,6 +55,47 @@ import { AutoDebugFeature } from 'aws-core-vscode/amazonq'
5555const localize = nls . loadMessageBundle ( )
5656const logger = getLogger ( 'amazonqLsp.lspClient' )
5757
58+ interface RetryOptions {
59+ maxAttempts : number
60+ initialDelayMs : number
61+ maxDelayMs : number
62+ backoffMultiplier : number
63+ onRetry ?: ( attempt : number , error : Error ) => void
64+ onFailure ?: ( attempts : number , lastError : Error ) => void
65+ }
66+
67+ /**
68+ * Retry a function with exponential backoff
69+ */
70+ async function retryWithExponentialBackoff < T > ( fn : ( ) => T | Promise < T > , options : RetryOptions ) : Promise < T > {
71+ const { maxAttempts, initialDelayMs, maxDelayMs, backoffMultiplier, onRetry, onFailure } = options
72+
73+ let lastError : Error
74+
75+ for ( let attempt = 1 ; attempt <= maxAttempts ; attempt ++ ) {
76+ try {
77+ return await fn ( )
78+ } catch ( error ) {
79+ lastError = error instanceof Error ? error : new Error ( String ( error ) )
80+
81+ if ( attempt === maxAttempts ) {
82+ onFailure ?.( attempt , lastError )
83+ throw lastError
84+ }
85+
86+ onRetry ?.( attempt , lastError )
87+
88+ // Calculate delay with exponential backoff
89+ const delay = Math . min ( initialDelayMs * Math . pow ( backoffMultiplier , attempt - 1 ) , maxDelayMs )
90+
91+ await new Promise ( ( resolve ) => setTimeout ( resolve , delay ) )
92+ }
93+ }
94+
95+ // This should never be reached, but TypeScript requires it
96+ throw lastError !
97+ }
98+
5899export function hasGlibcPatch ( ) : boolean {
59100 // Skip GLIBC patching for SageMaker environments
60101 if ( isSageMaker ( ) ) {
@@ -256,27 +297,38 @@ async function onLanguageServerReady(
256297 try {
257298 getLogger ( 'amazonqLsp' ) . debug ( 'Attempting to connect AutoDebug feature to language client' )
258299
259- // Function to attempt connection
260- const attemptConnection = ( attempt : number = 1 ) : void => {
261- const autoDebugFeature = ( global as any ) . autoDebugFeature as AutoDebugFeature | undefined
262-
263- if ( autoDebugFeature ) {
300+ await retryWithExponentialBackoff (
301+ ( ) => {
302+ const autoDebugFeature = ( global as any ) . autoDebugFeature as AutoDebugFeature | undefined
303+ if ( ! autoDebugFeature ) {
304+ throw new Error ( 'AutoDebug feature not available' )
305+ }
264306 autoDebugFeature . setLanguageClient ( client , encryptionKey )
265- } else if ( attempt < 5 ) {
266- // Retry up to 5 times with exponential backoff
267- const delay = Math . min ( 1000 * Math . pow ( 2 , attempt - 1 ) , 10000 ) // Max 10 seconds
268- setTimeout ( ( ) => attemptConnection ( attempt + 1 ) , delay )
269- } else {
270- getLogger ( 'amazonqLsp' ) . error (
271- 'AutoDebug feature not found after %d attempts - integration will not work. ' +
272- 'This may indicate that the AutoDebug feature failed to activate or there is a timing issue.' ,
273- attempt
274- )
307+ getLogger ( 'amazonqLsp' ) . debug ( 'AutoDebug feature connected successfully' )
308+ } ,
309+ {
310+ maxAttempts : 5 ,
311+ initialDelayMs : 1000 ,
312+ maxDelayMs : 10000 ,
313+ backoffMultiplier : 2 ,
314+ onRetry : ( attempt , error ) => {
315+ getLogger ( 'amazonqLsp' ) . debug (
316+ 'AutoDebug connection attempt %d failed: %s. Retrying...' ,
317+ attempt ,
318+ error . message
319+ )
320+ } ,
321+ onFailure : ( attempts , lastError ) => {
322+ getLogger ( 'amazonqLsp' ) . error (
323+ 'AutoDebug feature not found after %d attempts - integration will not work. ' +
324+ 'This may indicate that the AutoDebug feature failed to activate or there is a timing issue. ' +
325+ 'Last error: %s' ,
326+ attempts ,
327+ lastError . message
328+ )
329+ } ,
275330 }
276- }
277-
278- // Start the connection attempts
279- attemptConnection ( )
331+ )
280332 } catch ( error ) {
281333 getLogger ( 'amazonqLsp' ) . error ( 'Failed to connect AutoDebug feature to language client: %s' , error )
282334 }
0 commit comments