Skip to content

Commit 2be28eb

Browse files
UN-2454 [FIX] Resolve stale closure bug in polling state management
Use ref instead of state for pollingIds to prevent stale closure issues in polling logic: - Added pollingIdsRef to track actively polling execution IDs - Updated all polling operations to directly mutate ref (no re-renders needed) - Removed redundant pollingIds state to eliminate unnecessary re-renders - Prevents duplicate polling loops and potential memory leaks 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 944448c commit 2be28eb

File tree

1 file changed

+11
-18
lines changed

1 file changed

+11
-18
lines changed

frontend/src/components/logging/execution-logs/ExecutionLogs.jsx

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ function ExecutionLogs() {
4343
const [selectedDateRange, setSelectedDateRange] = useState([]);
4444
const [datePickerValue, setDatePickerValue] = useState(null);
4545
const [ordering, setOrdering] = useState(null);
46-
const [pollingIds, setPollingIds] = useState(new Set());
4746
// Store timeouts in a ref for proper cleanup
4847
const pollingTimeoutsRef = useRef({});
48+
// Store polling IDs in a ref to avoid stale closure issues
49+
const pollingIdsRef = useRef(new Set());
4950
const currentPath = location.pathname !== `/${sessionDetails?.orgName}/logs`;
5051
const items = [
5152
{
@@ -135,7 +136,8 @@ function ExecutionLogs() {
135136
clearTimeout(pollingTimeoutsRef.current[id]);
136137
}
137138
pollingTimeoutsRef.current = {};
138-
setPollingIds(new Set());
139+
// Reset ref to keep it in sync
140+
pollingIdsRef.current = new Set();
139141
};
140142

141143
const pollExecutingRecord = async (id) => {
@@ -174,11 +176,8 @@ function ExecutionLogs() {
174176

175177
// If status should no longer be polled, remove from polling
176178
if (!shouldPoll(item)) {
177-
setPollingIds((prev) => {
178-
const newSet = new Set(prev);
179-
newSet.delete(id);
180-
return newSet;
181-
});
179+
// Update ref to keep it in sync
180+
pollingIdsRef.current.delete(id);
182181
clearPollingTimeout(id);
183182
}
184183
}
@@ -193,23 +192,17 @@ function ExecutionLogs() {
193192
);
194193
}
195194
} catch (err) {
196-
setPollingIds((prev) => {
197-
const newSet = new Set(prev);
198-
newSet.delete(id);
199-
return newSet;
200-
});
195+
// Update ref to keep it in sync
196+
pollingIdsRef.current.delete(id);
201197
clearPollingTimeout(id);
202198
}
203199
};
204200

205201
const startPollingForExecuting = (records) => {
206202
for (const record of records) {
207-
if (shouldPoll(record) && !pollingIds.has(record.key)) {
208-
setPollingIds((prev) => {
209-
const newSet = new Set(prev);
210-
newSet.add(record.key);
211-
return newSet;
212-
});
203+
if (shouldPoll(record) && !pollingIdsRef.current.has(record.key)) {
204+
// Update ref immediately to prevent stale closure issues
205+
pollingIdsRef.current.add(record.key);
213206
pollExecutingRecord(record.key);
214207
}
215208
}

0 commit comments

Comments
 (0)