--- 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( condition: () => T | false | undefined | null, description: string, timeoutMs = 5000, pollMs = 10 ): Promise { 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