69 lines
1.7 KiB
Markdown
69 lines
1.7 KiB
Markdown
---
|
|
title: condition-based-waiting
|
|
type: note
|
|
permalink: opencode-config/skills/systematic-debugging/condition-based-waiting
|
|
---
|
|
|
|
# Condition-Based Waiting
|
|
|
|
## Overview
|
|
|
|
Arbitrary sleep durations create flaky tests and race conditions.
|
|
|
|
**Core principle:** wait for the condition that proves readiness, not a guessed delay.
|
|
|
|
## When to Use
|
|
|
|
Use this when:
|
|
- Tests rely on `sleep` or fixed `setTimeout` delays
|
|
- Asynchronous operations complete at variable speeds
|
|
- Tests pass locally but fail in CI or under load
|
|
|
|
Avoid arbitrary waits except when explicitly validating timing behavior (for example, debounce intervals), and document why timing-based waiting is necessary.
|
|
|
|
## Core Pattern
|
|
|
|
```ts
|
|
// ❌ Timing guess
|
|
await new Promise((r) => setTimeout(r, 100));
|
|
|
|
// ✅ Condition wait
|
|
await waitFor(() => getState() === 'ready', 'state ready');
|
|
```
|
|
|
|
## Generic Helper
|
|
|
|
```ts
|
|
async function waitFor<T>(
|
|
condition: () => T | false | undefined | null,
|
|
description: string,
|
|
timeoutMs = 5000,
|
|
pollMs = 10
|
|
): Promise<T> {
|
|
const started = Date.now();
|
|
|
|
while (true) {
|
|
const result = condition();
|
|
if (result) return result;
|
|
|
|
if (Date.now() - started > timeoutMs) {
|
|
throw new Error(`Timeout waiting for ${description} after ${timeoutMs}ms`);
|
|
}
|
|
|
|
await new Promise((r) => setTimeout(r, pollMs));
|
|
}
|
|
}
|
|
```
|
|
|
|
## Practical Guidance
|
|
|
|
- Keep polling intervals modest (for example, 10ms) to avoid hot loops.
|
|
- Always include a timeout and actionable error message.
|
|
- Query fresh state inside the loop; do not cache stale values outside it.
|
|
|
|
## Common Mistakes
|
|
|
|
- Polling too aggressively (high CPU, little benefit)
|
|
- Waiting forever without timeout
|
|
- Mixing arbitrary delays and condition checks without rationale
|