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
No known key found for this signature in database
GPG Key ID: 03E696BFD472B26A
6 changed files with 7 additions and 7 deletions

View File

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

View File

@ -174,8 +174,8 @@ const poll = async (
const delayedLoop = async (delayBy: number) => {
// Wait until we want to poll again
await setTimeout(delayBy);
// Poll again
await poll(false, fetchErrors);
// Poll again (use void to break recursion)
void poll(false, fetchErrors);
};
// 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
await setTimeout(delayBy);
// 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;
}
});
return null;
}
export async function applyIntermediateTarget(

View File

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

View File

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