Fixing a Search Race Condition with Google Gemini
This is a submission for DEVโs Summer Bug Smash: Clear the Lineup, powered by Sentry.
Project Overview
My project is a search application that helps users quickly find and explore records through a responsive interface. It communicates with an API and updates the displayed results whenever the search query changes.
The goal was to provide a fast and reliable search experience, even when users type quickly or have a slow network connection.
Bug Fix or Performance Improvement
The application had a race condition in its search feature.
Every change to the search input started a new API request. When users typed quickly, multiple requests ran simultaneously. A slower response from an earlier query could arrive after the latest response and overwrite the correct results.
For example, searching for react could incorrectly display results from the earlier query rea.
The application was also making unnecessary API requests for every keystroke, which affected performance and created an inconsistent loading experience.
Code
The main solution combines input debouncing with request cancellation:
useEffect(() => {
const controller = new AbortController();
const timeoutId = setTimeout(async () => {
try {
setLoading(true);
setError(null);
const response = await fetch(
`/api/search?q=${encodeURIComponent(searchQuery)}`,
{ signal: controller.signal }
);
if (!response.ok) {
throw new Error("Unable to load search results");
}
const data = await response.json();
setResults(data);
} catch (error) {
if (error.name !== "AbortError") {
setError(error.message);
}
} finally {
if (!controller.signal.aborted) {
setLoading(false);
}
}
}, 400);
return () => {
clearTimeout(timeoutId);
controller.abort();
};
}, [searchQuery]);
My Improvements
I fixed the problem through several focused improvements:
- Added a 400-millisecond debounce to avoid sending a request after every keystroke.
- Used
AbortControllerto cancel outdated requests. - Prevented canceled requests from appearing as application errors.
- Added clear loading, error, empty-result, and success states.
- Safely encoded search queries before sending them.
- Tested rapid typing, slow responses, failed requests, and empty results.
- Prevented stale responses from replacing the latest results.
I chose to use both debouncing and request cancellation. Debouncing reduces unnecessary requests, while cancellation protects the application when requests still overlap because of network latency.
After these changes, the search experience became faster, smoother, and more reliable.
Best Use of Google AI
I used Google Gemini as a development assistant while investigating and fixing the bug.
Gemini helped me:
- Analyze the asynchronous request flow.
- Identify the race condition.
- Compare possible solutions.
- Review the request-cancellation logic.
- Discover important edge cases.
- Develop test scenarios for rapid typing and slow responses.
- Improve error messages and code comments.
I carefully reviewed, adapted, and tested Geminiโs suggestions instead of using them without validation.
Google AI was especially helpful for turning an intermittent interface problem into a clear sequence of asynchronous events that I could reproduce and test. The final solution combined AI-assisted investigation with manual testing and engineering judgment.












