fix(cloud-agent): prevent false disconnects on idle cloud stream#2294
Conversation
315f484 to
7d8db81
Compare
Prompt To Fix All With AIFix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 2
apps/code/src/main/services/cloud-task/service.test.ts:672-694
**`makeInProgressRun` factory duplicated across six tests**
The `makeInProgressRun` arrow function with an identical `createJsonResponse` body is copy-pasted into at least six of the eight new test cases. This violates the OnceAndOnlyOnce principle the team follows. Hoisting it to a shared helper at the top of the `describe` block would remove ~50 lines of repetition and make future response-shape changes a single-point edit.
### Issue 2 of 2
apps/code/src/main/services/cloud-task/service.test.ts:1338
The budget comment lists six delay values (2 + 4 + 8 + 16 + 30 + 30 = 90 s) but the sixth delay is never scheduled — `scheduleReconnect` hits the `> MAX_SSE_RECONNECT_ATTEMPTS` guard immediately when `reconnectAttempts` reaches 6 and returns without enqueuing a timer. The real total backoff before the watcher is failed is 2 + 4 + 8 + 16 + 30 = 60 s (5 delays for 5 successful reconnects, 6th call fails immediately).
```suggestion
// Budget is 5 attempts (2s + 4s + 8s + 16s + 30s of backoff; the 6th call to
// scheduleReconnect fails the watcher immediately without adding another delay).
```
Reviews (1): Last reviewed commit: "fix(cloud-agent): prevent false disconne..." | Re-trigger Greptile |
| }); | ||
| }); | ||
|
|
||
| it("clears the backend-error budget after a healthy long-lived cut", async () => { | ||
| vi.useFakeTimers(); | ||
|
|
||
| const updates: unknown[] = []; | ||
| service.on(CloudTaskEvent.Update, (payload) => updates.push(payload)); | ||
|
|
||
| const makeInProgressRun = () => | ||
| createJsonResponse({ | ||
| id: "run-1", | ||
| status: "in_progress", | ||
| stage: null, | ||
| output: null, | ||
| error_message: null, | ||
| branch: "main", | ||
| updated_at: "2026-01-01T00:00:00Z", | ||
| }); | ||
|
|
||
| mockNetFetch | ||
| .mockResolvedValueOnce(makeInProgressRun()) // bootstrap: fetchTaskRun | ||
| .mockResolvedValueOnce( |
There was a problem hiding this comment.
makeInProgressRun factory duplicated across six tests
The makeInProgressRun arrow function with an identical createJsonResponse body is copy-pasted into at least six of the eight new test cases. This violates the OnceAndOnlyOnce principle the team follows. Hoisting it to a shared helper at the top of the describe block would remove ~50 lines of repetition and make future response-shape changes a single-point edit.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/main/services/cloud-task/service.test.ts
Line: 672-694
Comment:
**`makeInProgressRun` factory duplicated across six tests**
The `makeInProgressRun` arrow function with an identical `createJsonResponse` body is copy-pasted into at least six of the eight new test cases. This violates the OnceAndOnlyOnce principle the team follows. Hoisting it to a shared helper at the top of the `describe` block would remove ~50 lines of repetition and make future response-shape changes a single-point edit.
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| // 500s. The reconnect must charge the budget so it eventually gives up. | ||
| firstControllerRef.current?.close(); | ||
|
|
||
| // Budget is 5 attempts (2s + 4s + 8s + 16s + 30s + 30s of backoff). |
There was a problem hiding this comment.
The budget comment lists six delay values (2 + 4 + 8 + 16 + 30 + 30 = 90 s) but the sixth delay is never scheduled —
scheduleReconnect hits the > MAX_SSE_RECONNECT_ATTEMPTS guard immediately when reconnectAttempts reaches 6 and returns without enqueuing a timer. The real total backoff before the watcher is failed is 2 + 4 + 8 + 16 + 30 = 60 s (5 delays for 5 successful reconnects, 6th call fails immediately).
| // Budget is 5 attempts (2s + 4s + 8s + 16s + 30s + 30s of backoff). | |
| // Budget is 5 attempts (2s + 4s + 8s + 16s + 30s of backoff; the 6th call to | |
| // scheduleReconnect fails the watcher immediately without adding another delay). |
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/main/services/cloud-task/service.test.ts
Line: 1338
Comment:
The budget comment lists six delay values (2 + 4 + 8 + 16 + 30 + 30 = 90 s) but the sixth delay is never scheduled — `scheduleReconnect` hits the `> MAX_SSE_RECONNECT_ATTEMPTS` guard immediately when `reconnectAttempts` reaches 6 and returns without enqueuing a timer. The real total backoff before the watcher is failed is 2 + 4 + 8 + 16 + 30 = 60 s (5 delays for 5 successful reconnects, 6th call fails immediately).
```suggestion
// Budget is 5 attempts (2s + 4s + 8s + 16s + 30s of backoff; the 6th call to
// scheduleReconnect fails the watcher immediately without adding another delay).
```
How can I resolve this? If you propose a fix, please make it concise.
Problem
Idle runs (only keepalives flowing) were then falsely marked disconnected so keepalives never reset the reconnect counter and a clean transport cut counted as a failed attempt, so after a few cycles the watcher exhausted its retries and surfaced a spurious error. Rebooting would fix but of course not a great fix at that.
Changes