Skip to content

Commit 8997fa3

Browse files
committed
Update Subscription Executor
* Hook up models from cache to requests when app starting up * Removing requests after success or unretryable failure * To aid, the Executor maintains dict of subscription models it has seen, just like the user executor
1 parent a64ac01 commit 8997fa3

File tree

1 file changed

+75
-22
lines changed

1 file changed

+75
-22
lines changed

iOS_SDK/OneSignalSDK/OneSignalUser/Source/OSSubscriptionOperationExecutor.swift

Lines changed: 75 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
3535
var addRequestQueue: [OSRequestCreateSubscription] = []
3636
var removeRequestQueue: [OSRequestDeleteSubscription] = []
3737
var updateRequestQueue: [OSRequestUpdateSubscription] = []
38+
var subscriptionModels: [String: OSSubscriptionModel] = [:]
3839

3940
init() {
4041
// Read unfinished deltas from cache, if any...
@@ -56,20 +57,36 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
5657

5758
// Read unfinished requests from cache, if any...
5859

59-
if var addRequestQueue = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_ADD_REQUEST_QUEUE_KEY, defaultValue: []) as? [OSRequestCreateSubscription] {
60+
var requestQueue: [OSRequestCreateSubscription] = []
61+
62+
if var cachedAddRequestQueue = OneSignalUserDefaults.initShared().getSavedCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_ADD_REQUEST_QUEUE_KEY, defaultValue: []) as? [OSRequestCreateSubscription] {
6063
// Hook each uncached Request to the model in the store
61-
for (index, request) in addRequestQueue.enumerated().reversed() {
62-
if let subscriptionModel = getSubscriptionModelFromStores(modelId: request.subscriptionModel.modelId),
63-
let identityModel = OneSignalUserManagerImpl.sharedInstance.identityModelStore.getModel(modelId: request.identityModel.modelId) {
64-
// The models exist in the stores, set it to be the Request's models
64+
for request in cachedAddRequestQueue {
65+
// 1. Hook up the subscription model
66+
if let subscriptionModel = getSubscriptionModelFromStores(modelId: request.subscriptionModel.modelId) {
67+
// a. The model exist in the store, set it to be the Request's models
6568
request.subscriptionModel = subscriptionModel
69+
} else if let subscriptionModel = subscriptionModels[request.subscriptionModel.modelId] {
70+
// b. The model exists in the dictionary of seen models
71+
request.subscriptionModel = subscriptionModel
72+
} else {
73+
// c. The model has not been seen yet, add to dict
74+
subscriptionModels[request.subscriptionModel.modelId] = request.subscriptionModel
75+
}
76+
// 2. Hook up the identity model
77+
if let identityModel = OneSignalUserManagerImpl.sharedInstance.identityModelStore.getModel(modelId: request.identityModel.modelId) {
78+
// a. The model exist in the store
79+
request.identityModel = identityModel
80+
} else if let identityModel = OSUserExecutor.identityModels[request.identityModel.modelId] {
81+
// b. The model exist in the user executor
6682
request.identityModel = identityModel
6783
} else if !request.prepareForExecution() {
68-
// The models do not exist AND this request cannot be sent, drop this Request
69-
addRequestQueue.remove(at: index)
84+
// The model do not exist AND this request cannot be sent, drop this Request
85+
continue
7086
}
87+
requestQueue.append(request)
7188
}
72-
self.addRequestQueue = addRequestQueue
89+
self.addRequestQueue = requestQueue
7390
} else {
7491
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSSubscriptionOperationExecutor error encountered reading from cache for \(OS_SUBSCRIPTION_EXECUTOR_ADD_REQUEST_QUEUE_KEY)")
7592
}
@@ -78,10 +95,13 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
7895
// Hook each uncached Request to the model in the store
7996
for (index, request) in removeRequestQueue.enumerated().reversed() {
8097
if let subscriptionModel = getSubscriptionModelFromStores(modelId: request.subscriptionModel.modelId) {
81-
// The model exists in the store, set it to be the Request's model
98+
// 1. The model exists in the store, set it to be the Request's model
99+
request.subscriptionModel = subscriptionModel
100+
} else if let subscriptionModel = subscriptionModels[request.subscriptionModel.modelId] {
101+
// 2. The model exists in the dict of seen subscription models
82102
request.subscriptionModel = subscriptionModel
83103
} else if !request.prepareForExecution() {
84-
// The model does not exist AND this request cannot be sent, drop this Request
104+
// 3. The model does not exist AND this request cannot be sent, drop this Request
85105
removeRequestQueue.remove(at: index)
86106
}
87107
}
@@ -94,10 +114,13 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
94114
// Hook each uncached Request to the model in the store
95115
for (index, request) in updateRequestQueue.enumerated().reversed() {
96116
if let subscriptionModel = getSubscriptionModelFromStores(modelId: request.subscriptionModel.modelId) {
97-
// The model exists in the store, set it to be the Request's model
117+
// 1. The model exists in the store, set it to be the Request's model
118+
request.subscriptionModel = subscriptionModel
119+
} else if let subscriptionModel = subscriptionModels[request.subscriptionModel.modelId] {
120+
// 2. The model exists in the dict of seen subscription models
98121
request.subscriptionModel = subscriptionModel
99122
} else if !request.prepareForExecution() {
100-
// The models do not exist AND this request cannot be sent, drop this Request
123+
// 3. The models do not exist AND this request cannot be sent, drop this Request
101124
updateRequestQueue.remove(at: index)
102125
}
103126
}
@@ -202,13 +225,17 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
202225
}
203226

204227
func executeCreateSubscriptionRequest(_ request: OSRequestCreateSubscription) {
228+
guard !request.sentToClient else {
229+
return
230+
}
205231
guard request.prepareForExecution() else {
206232
return
207233
}
234+
request.sentToClient = true
235+
208236
OneSignalLog.onesignalLog(.LL_VERBOSE, message: "OSSubscriptionOperationExecutor: executeCreateSubscriptionRequest making request: \(request)")
209237
OneSignalClient.shared().execute(request) { result in
210238
// On success, remove request from cache (even if not hydrating model), and hydrate model
211-
// For example, if app restarts and we read in operations between sending this off and getting the response
212239
self.addRequestQueue.removeAll(where: { $0 == request})
213240
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue)
214241

@@ -217,17 +244,26 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
217244
return
218245
}
219246
request.subscriptionModel.hydrate(response)
220-
221247
} onFailure: { error in
222-
self.addRequestQueue.removeAll(where: { $0 == request})
223-
OneSignalLog.onesignalLog(.LL_ERROR, message: error.debugDescription)
248+
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSSubscriptionOperationExecutor create subscription request failed with error: \(error.debugDescription)")
249+
// TODO: Differentiate error cases
250+
// If the error is not retryable, remove from cache and queue
251+
if let nsError = error as? NSError,
252+
nsError.code < 500 && nsError.code != 0 {
253+
self.addRequestQueue.removeAll(where: { $0 == request})
254+
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue)
255+
}
224256
}
225257
}
226258

227259
func executeDeleteSubscriptionRequest(_ request: OSRequestDeleteSubscription) {
260+
guard !request.sentToClient else {
261+
return
262+
}
228263
guard request.prepareForExecution() else {
229264
return
230265
}
266+
request.sentToClient = true
231267

232268
// This request can be executed as-is.
233269
OneSignalLog.onesignalLog(.LL_VERBOSE, message: "OSSubscriptionOperationExecutor: executeDeleteSubscriptionRequest making request: \(request)")
@@ -239,17 +275,28 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
239275
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, withValue: self.removeRequestQueue)
240276

241277
} onFailure: { error in
242-
self.removeRequestQueue.removeAll(where: { $0 == request})
243-
OneSignalLog.onesignalLog(.LL_ERROR, message: error.debugDescription)
278+
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSSubscriptionOperationExecutor delete subscription request failed with error: \(error.debugDescription)")
279+
// TODO: Differentiate error cases
280+
// If the error is not retryable, remove from cache and queue
281+
if let nsError = error as? NSError,
282+
nsError.code < 500 && nsError.code != 0 {
283+
self.removeRequestQueue.removeAll(where: { $0 == request})
284+
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, withValue: self.removeRequestQueue)
285+
}
244286
}
245287
}
246288

247289
func executeUpdateSubscriptionRequest(_ request: OSRequestUpdateSubscription) {
248-
OneSignalLog.onesignalLog(.LL_VERBOSE, message: "OSSubscriptionOperationExecutor: executeUpdateSubscriptionRequest making request: \(request)")
249-
290+
guard !request.sentToClient else {
291+
return
292+
}
250293
guard request.prepareForExecution() else {
251294
return
252295
}
296+
request.sentToClient = true
297+
298+
OneSignalLog.onesignalLog(.LL_VERBOSE, message: "OSSubscriptionOperationExecutor: executeUpdateSubscriptionRequest making request: \(request)")
299+
253300
OneSignalClient.shared().execute(request) { _ in
254301

255302
// On success, remove request from cache. No model hydration occurs.
@@ -258,8 +305,14 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor {
258305
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY, withValue: self.updateRequestQueue)
259306

260307
} onFailure: { error in
261-
self.updateRequestQueue.removeAll(where: { $0 == request})
262-
OneSignalLog.onesignalLog(.LL_ERROR, message: error.debugDescription)
308+
OneSignalLog.onesignalLog(.LL_ERROR, message: "OSSubscriptionOperationExecutor update subscription request failed with error: \(error.debugDescription)")
309+
// TODO: Differentiate error cases
310+
// If the error is not retryable, remove from cache and queue
311+
if let nsError = error as? NSError,
312+
nsError.code < 500 && nsError.code != 0 {
313+
self.updateRequestQueue.removeAll(where: { $0 == request})
314+
OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY, withValue: self.updateRequestQueue)
315+
}
263316
}
264317
}
265318
}

0 commit comments

Comments
 (0)