Skip to content

[SDK-342] - AuthRetry logic#987

Open
Ayyanchira wants to merge 5 commits intoautoretry-masterfrom
feature/auto-retry
Open

[SDK-342] - AuthRetry logic#987
Ayyanchira wants to merge 5 commits intoautoretry-masterfrom
feature/auto-retry

Conversation

@Ayyanchira
Copy link
Member

@Ayyanchira Ayyanchira commented Feb 8, 2026

🔹 Jira Ticket(s) if any

✏️ Description

Adds automatic JWT retry for offline-queued requests. When a stored offline task receives a 401 JWT error, instead of retrying inline, the task is retained in the DB and task processing pauses until a fresh token is obtained.

Changes by file

IterableApi.java

  • Reads autoRetry flag from remote configuration and persists it in SharedPreferences.
  • Exposes package-private isAutoRetryOnJwtFailure() for internal use only (not customer-facing).

IterableAuthManager.java

  • Introduces AuthState enum (VALID, INVALID, UNKNOWN) to represent JWT token health.
  • Adds AuthTokenReadyListener pub/sub so components (e.g., IterableTaskRunner) can react when a new token is available.
  • handleAuthTokenSuccess sets state to UNKNOWN (new token, not yet verified); setIsLastAuthTokenValid(true) transitions to VALID.
  • State transitions from INVALID → non-INVALID notify listeners to resume processing.

IterableTaskRunner.java

  • Implements AuthTokenReadyListener. On JWT 401, marks auth INVALID, pauses processing, and returns RETRY without deleting the task.
  • On onAuthTokenReady() callback, resumes task processing with the fresh token.
  • Always uses the current live auth token (via authTokenOverride in fromJSON) instead of the stale one stored in the DB at queue time.

IterableRequestTask.java

  • When autoRetry is enabled and the request is offline, skips inline retry and schedules a delayed auth token refresh instead — IterableTaskRunner handles the retry.
  • Defensive null-check on getErrorStream() and responseCode >= 0 guard against network inspector interference returning -1.
  • Heuristic: if responseCode == -1 but response body contains JWT error codes, infers 401.
  • fromJSON overload accepts optional authTokenOverride for injecting fresh tokens into deserialized offline tasks.

OfflineRequestProcessor.java

  • Registers taskRunner as AuthTokenReadyListener on construction.
  • dispose() method unregisters the listener to prevent stale accumulation when offline mode is toggled.

IterableApiClient.java

  • Calls dispose() on the old OfflineRequestProcessor before replacing it in setOfflineProcessingEnabled().

Resolved concerns from earlier draft

  • IterableConfig.autoRetryOnJwtFailure should not be customer-facing → Removed from IterableConfig (commit be05ccb). Flag is now remote-config only.
  • fromJSON authTokenOverride purpose unclear → Used by TaskRunner.processTask() to inject fresh token into stale DB tasks. Correct architectural choice (task-management concern belongs in TaskRunner, not RequestTask).
  • isJwtFailure method redundant? → Kept as a small, well-named abstraction. In offline context, any 401 is treated as JWT failure since the API key was valid at queue time.
  • responseCode -1 handling → Defensive heuristic kept. Null errorStream check is valid per Android HttpURLConnection docs.

⚠️ Known issue discovered during testing (pre-existing, not introduced by this PR)

registerDeviceToken is called repeatedly on every JWT rotation.

setAuthToken() calls completeUserLogin() whenever the token string changes. completeUserLogin() unconditionally calls registerForPush(), syncInApp(), and syncMessages(). This means every JWT refresh (e.g. on expiration) triggers a full re-registration cycle even though the user identity (email/userId) and push token (FCM) haven't changed.

completeUserLogin was designed for user identity changes (setEmail/setUserId), where re-registering makes sense. But setAuthToken also triggers it on routine JWT rotation, causing unnecessary API calls. setAuthToken should distinguish between "new user login" and "credential refresh" to avoid redundant work.

Needs a separate ticket to address.

Copy link
Member Author

@Ayyanchira Ayyanchira left a comment

Choose a reason for hiding this comment

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

Self review until OfflienRequestProcessor.java

@Ayyanchira Ayyanchira changed the base branch from master to autoretry-master February 23, 2026 22:08
Includes
1. getRemoteConfiguration checking for the flag. And assuming false if no values exist. Also stores in sharedPreferences to load from it next time.
2. isAutoRetryOnJWTFailure on `IterableAPI` which other classes with use. Not public.
3. Introduced three states which Taskmanager can rely on. VALID, INVALID, UNKNOWN.
4. Listener pub/sub added which will invoke onAuthTokenReady() on listner class. Adding array of AuthTokenReadyListener on Authmanager and its add and remove list methods.
5. Right now authHandler null returns true hoping to bypass jwt. But JWT based request will fail if API needs jwt. This could pile up storage. But this seems like a valid scenario
6. handleAuthTokenSucess sets authtoken to unknown when a new token is set. I hope it should be right approach. Because its new and unknown at this point.
7. `IterableConfig` has final boolean `autoRetryOnJwtFailure`. Its not something I want customers to be able to configure. It should be removed before going to master. It should be internal only variable.
8. IterableRequestTask - has some changes introduced due to the flow not falling under jwt failure. Response code coming has -1 was the root cause. Hence the change around responseCode >= 0 && responseCode < 400
9. `IterableRequestTask` - Line 215 - Still not sure if RequestProcessor check should happen. It does make sense to have it as only offline stored request will be reprocessed. And this feature should only work for those requests going through offline Request processor
10. `IterableRequestTask` - fromJSON method change is something I havent checked properly. I think its for unit testing the changes are done.
11. IterableTaskRunner. Would like to see if I can remove the method - isJWTFailure(responseCode). May be its a small abstraction thats needed.
12. Havent checked unit tests properly yet
@franco-zalamena-iterable franco-zalamena-iterable marked this pull request as ready for review March 10, 2026 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants