@@ -174,18 +174,51 @@ export async function recoverOrphanedSubagentSessions(params: {
174174 return result ;
175175}
176176
177+ /** Maximum number of retry attempts for orphan recovery. */
178+ const MAX_RECOVERY_RETRIES = 3 ;
179+ /** Backoff multiplier between retries (exponential). */
180+ const RETRY_BACKOFF_MULTIPLIER = 2 ;
181+
177182/**
178- * Schedule orphan recovery after a delay.
183+ * Schedule orphan recovery after a delay, with retry logic .
179184 * The delay gives the gateway time to fully bootstrap after restart.
185+ * If recovery fails (e.g. gateway not yet ready), retries with exponential backoff.
180186 */
181187export function scheduleOrphanRecovery ( params : {
182188 getActiveRuns : ( ) => Map < string , SubagentRunRecord > ;
183189 delayMs ?: number ;
190+ maxRetries ?: number ;
184191} ) : void {
185- const delay = params . delayMs ?? DEFAULT_RECOVERY_DELAY_MS ;
186- setTimeout ( ( ) => {
187- void recoverOrphanedSubagentSessions ( params ) . catch ( ( err ) => {
188- log . warn ( `scheduled orphan recovery failed: ${ String ( err ) } ` ) ;
189- } ) ;
190- } , delay ) . unref ?.( ) ;
192+ const initialDelay = params . delayMs ?? DEFAULT_RECOVERY_DELAY_MS ;
193+ const maxRetries = params . maxRetries ?? MAX_RECOVERY_RETRIES ;
194+
195+ const attemptRecovery = ( attempt : number , delay : number ) => {
196+ setTimeout ( ( ) => {
197+ void recoverOrphanedSubagentSessions ( params )
198+ . then ( ( result ) => {
199+ if ( result . failed > 0 && attempt < maxRetries ) {
200+ const nextDelay = delay * RETRY_BACKOFF_MULTIPLIER ;
201+ log . info (
202+ `orphan recovery had ${ result . failed } failure(s); retrying in ${ nextDelay } ms (attempt ${ attempt + 1 } /${ maxRetries } )` ,
203+ ) ;
204+ attemptRecovery ( attempt + 1 , nextDelay ) ;
205+ }
206+ } )
207+ . catch ( ( err ) => {
208+ if ( attempt < maxRetries ) {
209+ const nextDelay = delay * RETRY_BACKOFF_MULTIPLIER ;
210+ log . warn (
211+ `scheduled orphan recovery failed: ${ String ( err ) } ; retrying in ${ nextDelay } ms (attempt ${ attempt + 1 } /${ maxRetries } )` ,
212+ ) ;
213+ attemptRecovery ( attempt + 1 , nextDelay ) ;
214+ } else {
215+ log . warn (
216+ `scheduled orphan recovery failed after ${ maxRetries } retries: ${ String ( err ) } ` ,
217+ ) ;
218+ }
219+ } ) ;
220+ } , delay ) . unref ?.( ) ;
221+ } ;
222+
223+ attemptRecovery ( 0 , initialDelay ) ;
191224}
0 commit comments