mirror of
https://github.com/Comfy-Org/comfy-swift-sdk.git
synced 2026-11-04 23:47:26 +00:00
[PR #3] [MERGED] fix(transport): retry transient errors on the execution_success output fetch #8
Labels
No labels
enhancement
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/comfy-swift-sdk#8
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/Comfy-Org/comfy-swift-sdk/pull/3
Author: @mattmillerai
Created: 6/19/2026
Status: ✅ Merged
Merged: 6/19/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-1606-comfy-ios-backgrounded-fast-job-recovers-but-the-output📝 Commits (3)
39c1eaefix(transport): treat POSIX socket-drop errors as transient so jobs recover via pollingd94aaebfix(transport): retry transient errors on the execution_success output fetchea35614merge: main into BE-1606 branch to drop redundant BE-1594 base (it squash-merged)📊 Changes
3 files changed (+428 additions, -22 deletions)
View changed files
📝
Sources/ComfySwiftSDK/Internal/PollingFallback.swift(+59 -11)📝
Sources/ComfySwiftSDK/Internal/WebSocketSession.swift(+25 -11)➕
Tests/ComfySwiftSDKTests/OutputFetchTransientRetryTests.swift(+344 -0)📄 Description
ELI5
The previous fix (merged as PR #2) stopped a backgrounded job from showing
an immediate false-failure on resume — but a job that finished while the
app was asleep could still fail ~20s later: fetching the output image over
the just-resumed connection hits a POSIX socket-drop (ECONNRESET), the
single
try/catchgave up, and the user saw an error on a job that actuallysucceeded. This PR wraps that output-fetch step in a bounded retry so the
result loads instead of erroring.
What
PollingFallback.swift: addedstatic func withTransientRetry<T>— 3attempts, 250 ms pause after the first failure, immediate propagation of
non-transient errors. Applied to every
downloadView/downloadViewToTempFilecall insidebuildOutputso the polling-recoveredpath also survives a stale-connection fetch.
WebSocketSession.swift: theexecution_successoutput-buildcatchblock now wraps each
downloadView/downloadViewToTempFilecall inPollingFallback.withTransientRetry. Non-transient errors still reachcontinuation.yield(.failed(...))exactly as before; transient errorsretry up to 3× before giving up.
OutputFetchTransientRetryTests.swift(new): 16 swift-testing testscovering the retry helper directly,
buildOutputviaTestURLProtocol(first
/api/viewthrowsECONNRESET, second succeeds), and the end-to-endpolling stream. Regression assertions confirm that empty output, auth
failures,
.cancelled, and.jobFailedare unchanged.Why
ECONNRESETon a freshly resumed socket is by definition transient —Transport.translate(from PR #2) already maps it to.network(transient),PollingFallback.isTransientalready returnstruefor it — but neitherthe WS output-build path nor
buildOutputused those classifications.This completes the picture: transient errors are retried at every
output-fetch boundary, not just at the poll-loop boundary.
Testing
Note: this fix was built stacked on #2; since #2 merged before this PR was
opened, the diff lands cleanly against main with the POSIX mapping already
present — the
ECONNRESET-is-transient assertion holds without anyadditional changes.
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.