Skip to content

Commit 0e1f4a9

Browse files
committed
Retry-After mapping to internal retryAfterSeconds
Add all the framework to parse Retry-After from the HTTP client layer, through to the code calling it, to the OperationRepo. This commit doesn't change any of the logic yet, but gets everything in place before making behavior changes and adding the tests.
1 parent 4c8652b commit 0e1f4a9

File tree

18 files changed

+173
-49
lines changed

18 files changed

+173
-49
lines changed

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/exceptions/BackendException.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,9 @@ class BackendException(
1212
* The response, if one exists.
1313
*/
1414
val response: String? = null,
15+
/**
16+
* Optional Integer value maybe returned from the backend.
17+
* The module handing this should delay any future requests by this time.
18+
*/
19+
val retryAfterSeconds: Int? = null,
1520
) : Exception()

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/backend/impl/ParamsBackendService.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ internal class ParamsBackendService(
3434
val response = _http.get(paramsUrl, CacheKeys.REMOTE_PARAMS)
3535

3636
if (!response.isSuccess) {
37-
throw BackendException(response.statusCode, response.payload)
37+
throw BackendException(response.statusCode, response.payload, response.retryAfterSeconds)
3838
}
3939

4040
val responseJson = JSONObject(response.payload!!)

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/config/ConfigModel.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ class ConfigModel : Model() {
111111
setIntProperty(::httpGetTimeout.name, value)
112112
}
113113

114+
/**
115+
* The fallback Retry-After to use if the header is present, but the server
116+
* give us a format we can't parse.
117+
*/
118+
var httpRetryAfterParseFailFallback: Int
119+
get() = getIntProperty(::httpRetryAfterParseFailFallback.name) { 60 }
120+
set(value) {
121+
setIntProperty(::httpRetryAfterParseFailFallback.name, value)
122+
}
123+
114124
/**
115125
* Maximum time in milliseconds a user can spend out of focus before a new session is created.
116126
*/

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/HttpResponse.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ class HttpResponse(
1818
* When non-null, the throwable that was thrown during processing.
1919
*/
2020
val throwable: Throwable? = null,
21+
/**
22+
* Optional Integer value maybe returned from the backend.
23+
* The module handing this should delay any future requests by this time.
24+
*/
25+
val retryAfterSeconds: Int? = null,
2126
) {
2227
/**
2328
* Whether the response is a successful one.

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/http/impl/HttpClient.kt

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ internal class HttpClient(
171171
// Network request is made from getResponseCode()
172172
httpResponse = con.responseCode
173173

174+
val retryAfter = retryAfterFromResponse(con)
175+
174176
when (httpResponse) {
175177
HttpURLConnection.HTTP_NOT_MODIFIED -> {
176178
val cachedResponse =
@@ -181,7 +183,7 @@ internal class HttpClient(
181183
Logging.debug("HttpClient: ${method ?: "GET"} $url - Using Cached response due to 304: " + cachedResponse)
182184

183185
// TODO: SHOULD RETURN OK INSTEAD OF NOT_MODIFIED TO MAKE TRANSPARENT?
184-
retVal = HttpResponse(httpResponse, cachedResponse)
186+
retVal = HttpResponse(httpResponse, cachedResponse, retryAfterSeconds = retryAfter)
185187
}
186188
HttpURLConnection.HTTP_ACCEPTED, HttpURLConnection.HTTP_CREATED, HttpURLConnection.HTTP_OK -> {
187189
val inputStream = con.inputStream
@@ -208,7 +210,7 @@ internal class HttpClient(
208210
}
209211
}
210212

211-
retVal = HttpResponse(httpResponse, json)
213+
retVal = HttpResponse(httpResponse, json, retryAfterSeconds = retryAfter)
212214
}
213215
else -> {
214216
Logging.debug("HttpClient: ${method ?: "GET"} $url - FAILED STATUS: $httpResponse")
@@ -229,7 +231,7 @@ internal class HttpClient(
229231
Logging.warn("HttpClient: $method HTTP Code: $httpResponse No response body!")
230232
}
231233

232-
retVal = HttpResponse(httpResponse, jsonResponse)
234+
retVal = HttpResponse(httpResponse, jsonResponse, retryAfterSeconds = retryAfter)
233235
}
234236
}
235237
} catch (t: Throwable) {
@@ -253,6 +255,22 @@ internal class HttpClient(
253255
return timeout + 5000
254256
}
255257

258+
/**
259+
* Reads the HTTP Retry-After from the response.
260+
* Only supports number format, not the date format.
261+
*/
262+
private fun retryAfterFromResponse(con: HttpURLConnection): Int? {
263+
val retryAfterStr = con.getHeaderField("Retry-After")
264+
return if (retryAfterStr != null) {
265+
Logging.debug("HttpClient: Response Retry-After: $retryAfterStr")
266+
retryAfterStr.toIntOrNull() ?: _configModelStore.model.httpRetryAfterParseFailFallback
267+
} else if (con.responseCode == 429) {
268+
_configModelStore.model.httpRetryAfterParseFailFallback
269+
} else {
270+
null
271+
}
272+
}
273+
256274
companion object {
257275
private const val OS_API_VERSION = "1"
258276
private const val OS_ACCEPT_HEADER = "application/vnd.onesignal.v$OS_API_VERSION+json"

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ class ExecutionResponse(
3737
* When specified, any operations that should be prepended to the operation repo.
3838
*/
3939
val operations: List<Operation>? = null,
40+
/**
41+
* Optional Integer value maybe returned from the backend.
42+
* The module handing this should delay any future requests by this time.
43+
*/
44+
val retryAfterSeconds: Int? = null,
4045
)
4146

4247
enum class ExecutionResult {

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/outcomes/impl/OutcomeEventsBackendService.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ internal class OutcomeEventsBackendService(private val _http: IHttpClient) :
4949
val response = _http.post("outcomes/measure", jsonObject)
5050

5151
if (!response.isSuccess) {
52-
throw BackendException(response.statusCode, response.payload)
52+
throw BackendException(response.statusCode, response.payload, response.retryAfterSeconds)
5353
}
5454
}
5555
}

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/IdentityBackendService.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ internal class IdentityBackendService(
2323
val response = _httpClient.patch("apps/$appId/users/by/$aliasLabel/$aliasValue/identity", requestJSONObject)
2424

2525
if (!response.isSuccess) {
26-
throw BackendException(response.statusCode, response.payload)
26+
throw BackendException(response.statusCode, response.payload, response.retryAfterSeconds)
2727
}
2828

2929
val responseJSON = JSONObject(response.payload!!)
@@ -40,7 +40,7 @@ internal class IdentityBackendService(
4040
val response = _httpClient.delete("apps/$appId/users/by/$aliasLabel/$aliasValue/identity/$aliasLabelToDelete")
4141

4242
if (!response.isSuccess) {
43-
throw BackendException(response.statusCode, response.payload)
43+
throw BackendException(response.statusCode, response.payload, response.retryAfterSeconds)
4444
}
4545
}
4646
}

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/SubscriptionBackendService.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ internal class SubscriptionBackendService(
2424
val response = _httpClient.post("apps/$appId/users/by/$aliasLabel/$aliasValue/subscriptions", requestJSON)
2525

2626
if (!response.isSuccess) {
27-
throw BackendException(response.statusCode, response.payload)
27+
throw BackendException(response.statusCode, response.payload, response.retryAfterSeconds)
2828
}
2929

3030
val responseJSON = JSONObject(response.payload!!)
@@ -48,7 +48,7 @@ internal class SubscriptionBackendService(
4848
val response = _httpClient.patch("apps/$appId/subscriptions/$subscriptionId", requestJSON)
4949

5050
if (!response.isSuccess) {
51-
throw BackendException(response.statusCode, response.payload)
51+
throw BackendException(response.statusCode, response.payload, response.retryAfterSeconds)
5252
}
5353
}
5454

@@ -59,7 +59,7 @@ internal class SubscriptionBackendService(
5959
val response = _httpClient.delete("apps/$appId/subscriptions/$subscriptionId")
6060

6161
if (!response.isSuccess) {
62-
throw BackendException(response.statusCode, response.payload)
62+
throw BackendException(response.statusCode, response.payload, response.retryAfterSeconds)
6363
}
6464
}
6565

@@ -76,7 +76,7 @@ internal class SubscriptionBackendService(
7676
val response = _httpClient.patch("apps/$appId/subscriptions/$subscriptionId/owner", requestJSON)
7777

7878
if (!response.isSuccess) {
79-
throw BackendException(response.statusCode, response.payload)
79+
throw BackendException(response.statusCode, response.payload, response.retryAfterSeconds)
8080
}
8181
}
8282

@@ -87,7 +87,7 @@ internal class SubscriptionBackendService(
8787
val response = _httpClient.get("apps/$appId/subscriptions/$subscriptionId/user/identity")
8888

8989
if (!response.isSuccess) {
90-
throw BackendException(response.statusCode, response.payload)
90+
throw BackendException(response.statusCode, response.payload, response.retryAfterSeconds)
9191
}
9292

9393
val responseJSON = JSONObject(response.payload!!)

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/backend/impl/UserBackendService.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ internal class UserBackendService(
3939
val response = _httpClient.post("apps/$appId/users", requestJSON)
4040

4141
if (!response.isSuccess) {
42-
throw BackendException(response.statusCode, response.payload)
42+
throw BackendException(response.statusCode, response.payload, response.retryAfterSeconds)
4343
}
4444

4545
return JSONConverter.convertToCreateUserResponse(JSONObject(response.payload!!))
@@ -68,7 +68,7 @@ internal class UserBackendService(
6868
val response = _httpClient.patch("apps/$appId/users/by/$aliasLabel/$aliasValue", jsonObject)
6969

7070
if (!response.isSuccess) {
71-
throw BackendException(response.statusCode, response.payload)
71+
throw BackendException(response.statusCode, response.payload, response.retryAfterSeconds)
7272
}
7373
}
7474

@@ -80,7 +80,7 @@ internal class UserBackendService(
8080
val response = _httpClient.get("apps/$appId/users/by/$aliasLabel/$aliasValue")
8181

8282
if (!response.isSuccess) {
83-
throw BackendException(response.statusCode, response.payload)
83+
throw BackendException(response.statusCode, response.payload, response.retryAfterSeconds)
8484
}
8585

8686
return JSONConverter.convertToCreateUserResponse(JSONObject(response.payload))

0 commit comments

Comments
 (0)