-
Notifications
You must be signed in to change notification settings - Fork 13
Open
Labels
enhancementNew feature or requestNew feature or request
Milestone
Description
Overview
Add automatic token refresh and retry when CloudKit returns authentication errors due to expired tokens.
Current Behavior
// Token expires during operation
let result = try await service.queryRecords(recordType: "Article")
// Throws: CloudKitError.unauthorized
// User must manually refresh token and retryProposed Behavior
// Automatic retry with token refresh
let result = try await service.queryRecords(recordType: "Article")
// If token expired:
// 1. Catches 401 Unauthorized
// 2. Refreshes token automatically
// 3. Retries operation transparently
// Returns result or throws non-auth errorBenefits
- Improved reliability: Operations don't fail due to timing issues
- Better UX: Fewer user-visible errors
- Simplified code: No manual retry logic needed
- Graceful degradation: Handles token expiration seamlessly
Implementation Approach
1. Add Retry Configuration
public struct RetryConfiguration {
/// Maximum number of retry attempts
public let maxAttempts: Int = 3
/// Which errors trigger retry
public let retryableErrors: Set<CloudKitError> = [.unauthorized]
/// Delay between retries (exponential backoff)
public let baseDelay: TimeInterval = 1.0
}2. Add Retry Middleware
internal actor RetryMiddleware: ClientMiddleware {
func intercept(
_ request: HTTPRequest,
next: (HTTPRequest) async throws -> HTTPResponse
) async throws -> HTTPResponse {
for attempt in 1...maxAttempts {
let response = try await next(request)
if response.status == .unauthorized && attempt < maxAttempts {
// Refresh token
try await tokenManager.refreshToken()
// Exponential backoff
try await Task.sleep(for: .seconds(baseDelay * pow(2, attempt - 1)))
continue // Retry
}
return response
}
}
}3. Integrate with CloudKitService
public init(
containerIdentifier: String,
tokenManager: any TokenManaging,
retryConfiguration: RetryConfiguration = .default
) {
// Add retry middleware to client
}Considerations
- Which operations should retry? Only read operations or writes too?
- Token refresh strategy: Different for WebAuthToken vs APIToken?
- Logging: Should retries be logged for debugging?
- Max attempts: What's reasonable? (suggest: 3)
- Backoff strategy: Exponential, linear, or fixed?
- Cancellation: Respect Task cancellation during retry delays?
Edge Cases
- Token refresh fails → propagate error immediately
- Multiple concurrent requests with expired token → coordinate refresh
- Server-to-Server auth → different refresh mechanism
- Rate limiting (429) → different retry strategy
Testing Strategy
- Mock token expiration scenarios
- Test concurrent request handling
- Verify exponential backoff timing
- Test cancellation during retry
- Verify max attempts limit
Related
- All authentication managers (APITokenManager, WebAuthTokenManager, etc.)
- CloudKitService error handling
- Middleware architecture
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request