1.7 KiB
1.7 KiB
title, type, permalink
| title | type | permalink |
|---|---|---|
| condition-based-waiting | note | 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
sleepor fixedsetTimeoutdelays - 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
// ❌ Timing guess
await new Promise((r) => setTimeout(r, 100));
// ✅ Condition wait
await waitFor(() => getState() === 'ready', 'state ready');
Generic Helper
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