Skip to content

Commit

Permalink
pause operation repo and retry on failed user create
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nan-li authored and jinliu9508 committed Feb 6, 2024
1 parent 473ca90 commit c98c49e
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,11 @@ enum class ExecutionResult {
* The operation failed due to a conflict and can be handled.
*/
FAIL_CONFLICT,

/**
* Used in special create user case.
* The operation failed due to a non-retryable error. Pause the operation repo
* and retry on a new session, giving the SDK a chance to recover from the failed user create.
*/
FAIL_PAUSE_OPREPO,
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ internal class OperationRepo(
private val executorsMap: Map<String, IOperationExecutor>
private val queue = mutableListOf<OperationQueueItem>()
private val waiter = WaiterWithValue<Boolean>()
private var paused = false

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

override fun start() {
paused = false
suspendifyOnThread(name = "OpRepo") {
processQueueForever()
}
Expand Down Expand Up @@ -99,6 +101,10 @@ internal class OperationRepo(

// This runs forever, until the application is destroyed.
while (true) {
if (paused) {
Logging.debug("OperationRepo is paused")
return
}
try {
var ops: List<OperationQueueItem>? = null

Expand Down Expand Up @@ -199,6 +205,15 @@ internal class OperationRepo(
ops.reversed().forEach { queue.add(0, it) }
}
}
ExecutionResult.FAIL_PAUSE_OPREPO -> {
Logging.error("Operation execution failed with eventual retry, pausing the operation repo: $operations")
// keep the failed operation and pause the operation repo from executing
paused = true
// add back all operations to the front of the queue to be re-executed.
synchronized(queue) {
ops.reversed().forEach { queue.add(0, it) }
}
}
}

// if there are operations provided on the result, we need to enqueue them at the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ internal class LoginUserOperationExecutor(
NetworkUtils.ResponseStatusType.UNAUTHORIZED ->
ExecutionResponse(ExecutionResult.FAIL_UNAUTHORIZED)
else ->
ExecutionResponse(ExecutionResult.FAIL_NORETRY)
ExecutionResponse(ExecutionResult.FAIL_PAUSE_OPREPO)
}
}
}
Expand Down

0 comments on commit c98c49e

Please sign in to comment.