Avoid leaking memory on deep promise recursions

The following pattern
```ts
async function longRunning() {
   // do something
   await setTimeout(delay);
   await longRunning();
}
```

Is regularly used for long running operations on the supervisor (e.g.
polling target state). We have
recently discovered that this pattern can slowly leak memory as it
essentially creates an infinite promise chain. Using `void longRunning()` breaks
the chain and avoids the issue.

This commit fixes all those instances where the pattern was used.

Change-type: patch
This commit is contained in:
Felipe Lalanne
2024-07-31 17:41:41 -04:00
parent 0124952962
commit d789e5bb77
6 changed files with 7 additions and 7 deletions

View File

@ -454,7 +454,7 @@ async function provisionOrRetry(retryDelay: number): Promise<void> {
delay: retryDelay, delay: retryDelay,
}); });
await setTimeout(retryDelay); await setTimeout(retryDelay);
return provisionOrRetry(retryDelay); void provisionOrRetry(retryDelay);
} }
} }

View File

@ -174,8 +174,8 @@ const poll = async (
const delayedLoop = async (delayBy: number) => { const delayedLoop = async (delayBy: number) => {
// Wait until we want to poll again // Wait until we want to poll again
await setTimeout(delayBy); await setTimeout(delayBy);
// Poll again // Poll again (use void to break recursion)
await poll(false, fetchErrors); void poll(false, fetchErrors);
}; };
// Check if we want to skip first request and just loop again // Check if we want to skip first request and just loop again

View File

@ -267,7 +267,8 @@ export async function startReporting() {
// Wait until we want to report again // Wait until we want to report again
await setTimeout(delayBy); await setTimeout(delayBy);
// Try to report again // Try to report again
await recursivelyReport(delayBy); // the void is necessary to break the recursion and avoid leaks
void recursivelyReport(delayBy);
} }
} }

View File

@ -759,7 +759,6 @@ export function triggerApplyTarget({
scheduledApply = null; scheduledApply = null;
} }
}); });
return null;
} }
export async function applyIntermediateTarget( export async function applyIntermediateTarget(

View File

@ -88,6 +88,6 @@ export async function loadBackupFromMigration(
log.error(`Error restoring migration backup, retrying: ${err}`); log.error(`Error restoring migration backup, retrying: ${err}`);
await setTimeout(retryDelay); await setTimeout(retryDelay);
return loadBackupFromMigration(targetState, retryDelay); void loadBackupFromMigration(targetState, retryDelay);
} }
} }

View File

@ -118,7 +118,7 @@ class LogMonitor {
}s`, }s`,
); );
await setTimeout(wait); await setTimeout(wait);
return this.start(); void this.start();
} }
public isAttached(containerId: string): boolean { public isAttached(containerId: string): boolean {