Skip to content

Commit 0cf1eb9

Browse files
committed
pause operation repo and retry on failed user create
Successful user creation is vital to the functioning of the SDK. Problem: If the create user request fails with an un-retryable error such as a 400 response, the SDK would not retry and stay in an unrecoverable error state with no onesignal_id, and no subscription_id (potentially). Therefore, it would never register, send data, or receive notifications. The only way out was to uninstall the app. Solution: Let's give the SDK a chance to recover from failed user creation, similar to the behavior of the iOS SDK. When met with this error, we will pause the operation repo from executing any more operations as it is impossible to do anything without a onesignal_id. Then, on new sessions or new cold starts, we will retry the still-cached operation, in the hopes that perhaps it can succeed at this later date.
1 parent ff841f9 commit 0cf1eb9

File tree

3 files changed

+23
-1
lines changed

3 files changed

+23
-1
lines changed

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/IOperationExecutor.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,11 @@ enum class ExecutionResult {
7171
* The operation failed due to a conflict and can be handled.
7272
*/
7373
FAIL_CONFLICT,
74+
75+
/**
76+
* Used in special create user case.
77+
* The operation failed due to a non-retryable error. Pause the operation repo
78+
* and retry on a new session, giving the SDK a chance to recover from the failed user create.
79+
*/
80+
FAIL_PAUSE_OPREPO,
7481
}

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/impl/OperationRepo.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ internal class OperationRepo(
3030
private val executorsMap: Map<String, IOperationExecutor>
3131
private val queue = mutableListOf<OperationQueueItem>()
3232
private val waiter = WaiterWithValue<Boolean>()
33+
private var paused = false
3334

3435
init {
3536
val executorsMap: MutableMap<String, IOperationExecutor> = mutableMapOf()
@@ -47,6 +48,7 @@ internal class OperationRepo(
4748
}
4849

4950
override fun start() {
51+
paused = false
5052
suspendifyOnThread(name = "OpRepo") {
5153
processQueueForever()
5254
}
@@ -99,6 +101,10 @@ internal class OperationRepo(
99101

100102
// This runs forever, until the application is destroyed.
101103
while (true) {
104+
if (paused) {
105+
Logging.debug("OperationRepo is paused")
106+
return
107+
}
102108
try {
103109
var ops: List<OperationQueueItem>? = null
104110

@@ -199,6 +205,15 @@ internal class OperationRepo(
199205
ops.reversed().forEach { queue.add(0, it) }
200206
}
201207
}
208+
ExecutionResult.FAIL_PAUSE_OPREPO -> {
209+
Logging.error("Operation execution failed with eventual retry, pausing the operation repo: $operations")
210+
// keep the failed operation and pause the operation repo from executing
211+
paused = true
212+
// add back all operations to the front of the queue to be re-executed.
213+
synchronized(queue) {
214+
ops.reversed().forEach { queue.add(0, it) }
215+
}
216+
}
202217
}
203218

204219
// if there are operations provided on the result, we need to enqueue them at the

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/LoginUserOperationExecutor.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ internal class LoginUserOperationExecutor(
205205
NetworkUtils.ResponseStatusType.UNAUTHORIZED ->
206206
ExecutionResponse(ExecutionResult.FAIL_UNAUTHORIZED)
207207
else ->
208-
ExecutionResponse(ExecutionResult.FAIL_NORETRY)
208+
ExecutionResponse(ExecutionResult.FAIL_PAUSE_OPREPO)
209209
}
210210
}
211211
}

0 commit comments

Comments
 (0)