Repository navigation
fix(workspace): resend an idempotent Nextcloud request once when it lands on a socket the server already closed (workspace 0.2.3) - #537
Merged
Conversation
…ands on a socket the server already closed (workspace 0.2.3) A long synchronous repeat expansion (T10-I2's dense rule took 6.6 s on the CI runner) blocks the event loop past the server's 5 s keep-alive timeout; fetch then reuses the closed pooled socket, the next request dies with ECONNRESET and ncFetch answered workspace_unreachable. That was the T10-I3 calendar flake, and the real Workspace server has the same hazard against Nextcloud. ncFetch now resends once, on a fresh connection, for ECONNRESET/EPIPE/ UND_ERR_SOCKET on GET/HEAD/OPTIONS/PROPFIND/REPORT/SEARCH/PUT/DELETE only. POST/MOVE/MKCOL/PROPPATCH/LOCK, timeouts and refused connections are never resent. New tests/workspace-nc-http.test.js covers both sides. Claude-Session: https://claude.ai/code/session_01N9fXzvNy8rCEArj1y5p6fp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was failing
tests/workspace-calendar.test.js"T10-I3: after_etag comes from the PUT's ETag…" failed in CI (seen on #535, and once in a local full suite) withCannot read properties of undefined (reading 'uid'):ws_cal_create_eventansweredworkspace_unreachable("connection failed").Root cause
It depends on load, not on the date or on test order.
fetchnever sees the close in time and sends T10-I3's first request (the calendar PROPFIND) on that socket. The request fails withECONNRESET, andncFetchmaps that toworkspace_unreachable.fetch failed / ECONNRESETon the PROPFIND). Blocking for 2.5 s or less passes.The product has the same hazard. A real Nextcloud (Apache) also drops idle keep-alive sockets after a few seconds, and the same dense expansion blocks the real Workspace server too, so the next tool call could fail with "Crow Workspace did not answer".
Fix
ncFetch(bundles/workspace/server/nc/http.js) resends a request once when it fails with a stale-socket reset (ECONNRESET/EPIPE/UND_ERR_SOCKET). The resend goes on a fresh connection, and only for methods that are safe to send twice: GET, HEAD, OPTIONS, PROPFIND, REPORT, SEARCH, PUT and DELETE. A conditional PUT whose first attempt did land answers 412, which becomeschanged_concurrently, never a double write. Some failures are never resent:Workspace manifest bumped to 0.2.3 (registry regenerated).
Tests
tests/workspace-nc-http.test.jsuses a server that resets the second request on a kept-alive socket. It checks that each idempotent method is resent once on a new connection, that POST and MOVE go out exactly once and fail asworkspace_unreachable, and that a refused connection is not retried. The resend cases fail without the fix and pass with it.tests/workspace-calendar.test.jspasses, including with a 6 to 7 s forced event-loop block before T10-I3 (it failed 100% that way before the fix).taskset -c 0-11,16-27 npm test).https://claude.ai/code/session_01N9fXzvNy8rCEArj1y5p6fp