Skip to content

Commit 70c8d6d

Browse files
fix(react-hooks): prevent onComplete from firing prematurely when stream disconnects (#2929)
## Summary Fixes #2856 - The `onComplete` callback in `useRealtimeRun` was firing prematurely ## Root Cause The callback was triggered when the long-poll stream ended, regardless of whether the run had actually completed. Reverse proxies often close idle connections, causing the stream to end prematurely. In this case it was caused by fetch abort due to React strict mode. ## Fix Changed the condition from checking if `run` exists to checking if `run?.finishedAt` exists, ensuring `onComplete` only fires when the run has reached a terminal state. --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: nicktrn <nicktrn@users.noreply.github.com>
1 parent eeab6bd commit 70c8d6d

File tree

2 files changed

+11
-2
lines changed

2 files changed

+11
-2
lines changed

.changeset/calm-hooks-wait.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@trigger.dev/react-hooks": patch
3+
---
4+
5+
Fix `onComplete` callback firing prematurely when the realtime stream disconnects before the run finishes.

packages/react-hooks/src/hooks/useRealtime.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,10 @@ export function useRealtimeRun<TTask extends AnyTask>(
149149
const hasCalledOnCompleteRef = useRef(false);
150150

151151
// Effect to handle onComplete callback
152+
// Only call onComplete when the run has actually finished (has finishedAt),
153+
// not just when the subscription stream ends (which can happen due to network issues)
152154
useEffect(() => {
153-
if (isComplete && run && options?.onComplete && !hasCalledOnCompleteRef.current) {
155+
if (isComplete && run?.finishedAt && options?.onComplete && !hasCalledOnCompleteRef.current) {
154156
options.onComplete(run, error);
155157
hasCalledOnCompleteRef.current = true;
156158
}
@@ -313,8 +315,10 @@ export function useRealtimeRunWithStreams<
313315
const hasCalledOnCompleteRef = useRef(false);
314316

315317
// Effect to handle onComplete callback
318+
// Only call onComplete when the run has actually finished (has finishedAt),
319+
// not just when the subscription stream ends (which can happen due to network issues)
316320
useEffect(() => {
317-
if (isComplete && run && options?.onComplete && !hasCalledOnCompleteRef.current) {
321+
if (isComplete && run?.finishedAt && options?.onComplete && !hasCalledOnCompleteRef.current) {
318322
options.onComplete(run, error);
319323
hasCalledOnCompleteRef.current = true;
320324
}

0 commit comments

Comments
 (0)