Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(typescript-client): Replace the while(true) in createFetchWithBackoff with a run closure + setTimeout #2366

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/six-apes-push.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@electric-sql/client": patch
---

Fix an issue on iOS where a shape would silently stop updating if the tab was moved into the background then back into the foreground. #2364
28 changes: 17 additions & 11 deletions packages/typescript-client/src/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,11 @@ export function createFetchWithBackoff(
let delay = initialDelay
let attempt = 0

/* eslint-disable no-constant-condition -- we re-fetch the shape log
* continuously until we get a non-ok response. For recoverable errors,
* we retry the fetch with exponential backoff. Users can pass in an
* AbortController to abort the fetching an any point.
* */
while (true) {
/* eslint-enable no-constant-condition */
/* We re-fetch the shape log continuously until we get a non-ok response.
* For recoverable errors, we retry the fetch with exponential backoff.
* Users can pass in an AbortController to abort the fetching at any point.
*/
const run = async (): Promise<Response> => {
try {
const result = await fetchClient(...args)
if (result.ok) return result
Expand All @@ -79,19 +77,27 @@ export function createFetchWithBackoff(
throw e
} else {
// Exponentially backoff on errors.
// Wait for the current delay duration
await new Promise((resolve) => setTimeout(resolve, delay))

// Capture current delay before increasing it
const currentDelay = delay
// Increase the delay for the next attempt
delay = Math.min(delay * multiplier, maxDelay)

if (debug) {
attempt++
console.log(`Retry attempt #${attempt} after ${delay}ms`)
console.log(`Retry attempt #${attempt} after ${currentDelay}ms`)
}

// Return a new promise that will resolve with the next run after the delay
return new Promise((resolve, reject) => {
setTimeout(() => {
run().then(resolve).catch(reject)
}, currentDelay)
})
}
}
}

return run()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we don't await anything inside the async function that is returned on L50 (only within the nested run function) we can remove the async keyword on L50.

}
}

Expand Down
Loading