Prompt
Avoid circular dependencies in asynchronous code paths that can lead to deadlocks or indefinite blocking. When using async/await, ensure that promise chains have clear resolution paths and aren’t dependent on their own completion. Be particularly careful with initialization patterns and refresh mechanisms.
Example of problematic code:
// PROBLEMATIC: Creates a deadlock
public async getSessions(): Promise<AuthSession[]> {
await this.initialRefreshAttempt; // Waits for refresh to complete
// ...
}
private async refreshSessions(): Promise<void> {
const sessions = await this.getSessions(); // Calls getSessions which waits for refreshSessions
// ...
}
constructor() {
this.initialRefreshAttempt = this.refreshSessions();
}
Example of fixed code:
// FIXED: Avoids deadlock by breaking circular dependency
public async getSessions(): Promise<AuthSession[]> {
// Don't await initialRefreshAttempt here
// ...
}
private async refreshSessions(): Promise<void> {
const sessions = await this.getSessions();
// ...
}
constructor() {
this.initialRefreshAttempt = this.refreshSessions();
}
Additionally:
- Always provide ways to cancel async operations (e.g., expose AbortController) to prevent resource leaks
- Be careful with race conditions when checking state that might change during async operations
- Analyze promise chains during code review to identify potential circular dependencies
- Use centralized managers for coordinating related async operations when appropriate