Skip to content

Commit d62669d

Browse files
committed
Add retry mechanism for CloudKit authentication
Implement exponential backoff retry logic to handle intermittent CloudKit authentication failures, particularly 421 status codes and UNKNOWN_ERROR responses. The mechanism retries up to 3 times with increasing delays (1s, 2s, 4s) to improve the reliability of CloudKit integration. - Add a retry loop with exponential backoff in the setupAuth function - Handle specific error types (421 status, UNKNOWN_ERROR) - Preserve original authentication flow for successful cases - Add wide error logging and final error handling
1 parent 8331a18 commit d62669d

File tree

1 file changed

+40
-6
lines changed

1 file changed

+40
-6
lines changed

src/components/Cloudkit.ts

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,50 @@ export function useCloudkit() {
3737

3838
useEffect(() => {
3939
const setupAuth = async (ck: CloudKit) => {
40-
const appleId = await ck.getDefaultContainer().setUpAuth();
41-
if (appleId) {
42-
setAppleSignedIn(true);
43-
} else {
44-
setAppleSignedIn(false);
40+
// CloudKit authentication with retry mechanism
41+
const MAX_RETRIES = 3;
42+
const MAX_DELAY = 8000; // Cap at 8 seconds
43+
let attempt = 0;
44+
let delay = 1000; // Start with 1 second
45+
46+
while (attempt < MAX_RETRIES) {
47+
attempt++;
48+
try {
49+
const appleId = await ck.getDefaultContainer().setUpAuth();
50+
if (appleId) {
51+
setAppleSignedIn(true);
52+
return; // Success
53+
}
54+
// If appleId is null but no error, it's a valid state (user not signed in)
55+
setAppleSignedIn(false);
56+
return;
57+
} catch (error: any) {
58+
const isRetryableError = error?.status === 421 || error?.ckErrorCode === "UNKNOWN_ERROR";
59+
const isLastAttempt = attempt >= MAX_RETRIES;
60+
61+
console.warn(`CloudKit auth attempt ${attempt}/${MAX_RETRIES} failed:`, error);
62+
63+
if (isRetryableError && !isLastAttempt) {
64+
console.log(`Retrying CloudKit auth in ${delay}ms due to transient error...`);
65+
await new Promise((resolve) => setTimeout(resolve, delay));
66+
delay = Math.min(delay * 2, MAX_DELAY); // Exponential backoff with cap
67+
} else {
68+
// Either non-retryable error or last attempt failed, re-throw the error to be handled elsewhere if needed
69+
setAppleSignedIn(false);
70+
throw error;
71+
}
72+
}
4573
}
74+
// Fallback: should never reach here, but defensive programming
75+
setAppleSignedIn(false);
76+
throw new Error("CloudKit authentication failed");
4677
};
4778

4879
if (cloudkit) {
49-
setupAuth(cloudkit);
80+
setupAuth(cloudkit).catch((err) => {
81+
console.error("CloudKit authentication failed after all retries:", err);
82+
// Optionally set an error state here to show in the UI
83+
});
5084
}
5185
}, [cloudkit]);
5286

0 commit comments

Comments
 (0)