Skip to content

Commit 8f5bc0a

Browse files
author
Alexis Oyama
committed
fix(request): Fixed when requests sent in order was blocking the main thread
1 parent 88b3e5d commit 8f5bc0a

File tree

3 files changed

+67
-65
lines changed

3 files changed

+67
-65
lines changed

Leanplum-SDK/Classes/LPNetworkOperation.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ - (void)cancel
139139
if (self.task) {
140140
[self.task suspend];
141141
}
142+
[self.session finishTasksAndInvalidate];
142143
}
143144

144145
- (void)run

Leanplum-SDK/Classes/LPVarCache.m

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,9 @@ + (LPVar *)getVariable:(NSString *)name
229229

230230
+ (void)computeMergedDictionary
231231
{
232-
merged = [self mergeHelper:valuesFromClient withDiffs:diffs];
232+
@synchronized (diffs) {
233+
merged = [self mergeHelper:valuesFromClient withDiffs:diffs];
234+
}
233235
}
234236

235237
+ (id)mergeHelper:(id)vars withDiffs:(id)diff
@@ -422,30 +424,31 @@ + (void)saveDiffs
422424
RETURN_IF_NOOP;
423425
// Stores the variables on the device in case we don't have a connection
424426
// next time the app is opened.
425-
426-
NSMutableData *diffsData = [[NSMutableData alloc] init];
427-
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:diffsData];
428-
[archiver encodeObject:diffs forKey:LEANPLUM_DEFAULTS_VARIABLES_KEY];
429-
[archiver encodeObject:messages forKey:LEANPLUM_DEFAULTS_MESSAGES_KEY];
430-
[archiver encodeObject:updateRulesDiffs forKey:LEANPLUM_DEFAULTS_UPDATE_RULES_KEY];
431-
[archiver encodeObject:eventRulesDiffs forKey:LEANPLUM_DEFAULTS_EVENT_RULES_KEY];
432-
[archiver encodeObject:variants forKey:LP_KEY_VARIANTS];
433-
[archiver encodeObject:regions forKey:LP_KEY_REGIONS];
434-
[archiver encodeObject:[LPConstantsState sharedState].sdkVersion forKey:LP_PARAM_SDK_VERSION];
435-
[archiver encodeObject:LeanplumRequest.deviceId forKey:LP_PARAM_DEVICE_ID];
436-
[archiver encodeObject:LeanplumRequest.userId forKey:LP_PARAM_USER_ID];
437-
[archiver encodeBool:[LPConstantsState sharedState].loggingEnabled forKey:LP_KEY_LOGGING_ENABLED];
438-
[archiver finishEncoding];
439-
440-
NSData *encryptedDiffs = [LPAES encryptedDataFromData:diffsData];
441-
442-
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
443-
444-
[defaults setObject:encryptedDiffs forKey:LEANPLUM_DEFAULTS_VARIABLES_KEY];
445-
446-
[defaults setObject:LEANPLUM_SDK_VERSION forKey:LEANPLUM_DEFAULTS_SDK_VERSION];
447-
448-
[Leanplum synchronizeDefaults];
427+
@synchronized (diffs) {
428+
NSMutableData *diffsData = [[NSMutableData alloc] init];
429+
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:diffsData];
430+
[archiver encodeObject:diffs forKey:LEANPLUM_DEFAULTS_VARIABLES_KEY];
431+
[archiver encodeObject:messages forKey:LEANPLUM_DEFAULTS_MESSAGES_KEY];
432+
[archiver encodeObject:updateRulesDiffs forKey:LEANPLUM_DEFAULTS_UPDATE_RULES_KEY];
433+
[archiver encodeObject:eventRulesDiffs forKey:LEANPLUM_DEFAULTS_EVENT_RULES_KEY];
434+
[archiver encodeObject:variants forKey:LP_KEY_VARIANTS];
435+
[archiver encodeObject:regions forKey:LP_KEY_REGIONS];
436+
[archiver encodeObject:[LPConstantsState sharedState].sdkVersion forKey:LP_PARAM_SDK_VERSION];
437+
[archiver encodeObject:LeanplumRequest.deviceId forKey:LP_PARAM_DEVICE_ID];
438+
[archiver encodeObject:LeanplumRequest.userId forKey:LP_PARAM_USER_ID];
439+
[archiver encodeBool:[LPConstantsState sharedState].loggingEnabled forKey:LP_KEY_LOGGING_ENABLED];
440+
[archiver finishEncoding];
441+
442+
NSData *encryptedDiffs = [LPAES encryptedDataFromData:diffsData];
443+
444+
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
445+
446+
[defaults setObject:encryptedDiffs forKey:LEANPLUM_DEFAULTS_VARIABLES_KEY];
447+
448+
[defaults setObject:LEANPLUM_SDK_VERSION forKey:LEANPLUM_DEFAULTS_SDK_VERSION];
449+
450+
[Leanplum synchronizeDefaults];
451+
}
449452
}
450453

451454
+ (void)applyVariableDiffs:(NSDictionary *)diffs_

Leanplum-SDK/Classes/LeanplumRequest.m

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -308,55 +308,37 @@ - (void)sendRequests:(BOOL)async
308308
{
309309
void (^operationBlock)() = ^void() {
310310
[LeanplumRequest generateUUID];
311+
lastSentTime = [NSDate timeIntervalSinceReferenceDate];
312+
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
311313

312314
// Simulate pop all requests.
313315
NSArray *requestsToSend = [LPEventDataManager eventsWithLimit:MAX_EVENTS_PER_API_CALL];
314-
lastSentTime = [NSDate timeIntervalSinceReferenceDate];
315-
316316
if (requestsToSend.count == 0) {
317317
return;
318318
}
319319

320+
// Set up request operation.
320321
NSString *requestData = [LPJSON stringFromJSON:@{LP_PARAM_DATA:requestsToSend}];
322+
NSString *timestamp = [NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]];
321323
LPConstantsState *constants = [LPConstantsState sharedState];
322-
NSMutableDictionary *multiRequestArgs = [NSMutableDictionary dictionaryWithObjectsAndKeys:
323-
requestData, LP_PARAM_DATA,
324-
constants.sdkVersion, LP_PARAM_SDK_VERSION,
325-
constants.client, LP_PARAM_CLIENT,
326-
LP_METHOD_MULTI, LP_PARAM_ACTION,
327-
[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]], LP_PARAM_TIME, nil];
324+
NSMutableDictionary *multiRequestArgs = [@{
325+
LP_PARAM_DATA: requestData,
326+
LP_PARAM_SDK_VERSION: constants.sdkVersion,
327+
LP_PARAM_CLIENT: constants.client,
328+
LP_PARAM_ACTION: LP_METHOD_MULTI,
329+
LP_PARAM_TIME: timestamp
330+
} mutableCopy];
328331
[self attachApiKeys:multiRequestArgs];
329332
int timeout = async ? constants.networkTimeoutSeconds : constants.syncNetworkTimeoutSeconds;
330333
id<LPNetworkOperationProtocol> op = [engine operationWithPath:constants.apiServlet
331334
params:multiRequestArgs
332335
httpMethod:_httpMethod
333336
ssl:constants.apiSSL
334337
timeoutSeconds:timeout];
335-
__block BOOL finished = NO;
336-
337-
// Schedule timeout.
338-
[LPTimerBlocks scheduledTimerWithTimeInterval:timeout block:^() {
339-
if (finished) {
340-
return;
341-
}
342-
finished = YES;
343-
LP_TRY
344-
NSLog(@"Leanplum: Request %@ timed out", _apiMethod);
345-
[op cancel];
346-
if (_error != nil) {
347-
_error([NSError errorWithDomain:@"Leanplum" code:1
348-
userInfo:@{NSLocalizedDescriptionKey: @"Request timed out"}]);
349-
}
350-
LP_END_TRY
351-
} repeats:NO];
352338

339+
// Request callbacks.
353340
[op addCompletionHandler:^(id<LPNetworkOperationProtocol> operation, id json) {
354-
if (finished) {
355-
return;
356-
}
357-
finished = YES;
358341
LP_TRY
359-
360342
// Handle errors that don't return an HTTP error code.
361343
NSUInteger numResponses = [LPResponse numResponsesInDictionary:json];
362344
for (NSUInteger i = 0; i < numResponses; i++) {
@@ -374,6 +356,7 @@ - (void)sendRequests:(BOOL)async
374356
_error([NSError errorWithDomain:@"Leanplum" code:2
375357
userInfo:@{NSLocalizedDescriptionKey: errorMessage}]);
376358
}
359+
dispatch_semaphore_signal(semaphore);
377360
return;
378361
}
379362
}
@@ -386,15 +369,14 @@ - (void)sendRequests:(BOOL)async
386369
if (requestsToSend.count == MAX_EVENTS_PER_API_CALL) {
387370
[self sendRequests:async];
388371
}
372+
dispatch_semaphore_signal(semaphore);
389373
LP_END_TRY
374+
390375
if (_response != nil) {
391376
_response(operation, json);
392377
}
378+
393379
} errorHandler:^(id<LPNetworkOperationProtocol> completedOperation, NSError *err) {
394-
if (finished) {
395-
return;
396-
}
397-
finished = YES;
398380
LP_TRY
399381
NSInteger httpStatusCode = completedOperation.HTTPStatusCode;
400382
if (httpStatusCode == 408
@@ -430,19 +412,30 @@ - (void)sendRequests:(BOOL)async
430412
if (_error != nil) {
431413
_error(err);
432414
}
415+
dispatch_semaphore_signal(semaphore);
433416
LP_END_TRY
434417
}];
435418

436419
// Execute synchronously. Don't block for more than 'timeout' seconds.
437-
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
438-
[engine runSynchronously:op];
439-
});
440-
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
441-
while (!finished && [[NSDate date] timeIntervalSince1970] - startTime < timeout) {
442-
[NSThread sleepForTimeInterval:0.1];
420+
[engine enqueueOperation:op];
421+
dispatch_time_t dispatchTimeout = dispatch_time(DISPATCH_TIME_NOW, timeout*NSEC_PER_SEC);
422+
long status = dispatch_semaphore_wait(semaphore, dispatchTimeout);
423+
424+
// Request timed out.
425+
if (status != 0) {
426+
LP_TRY
427+
NSLog(@"Leanplum: Request %@ timed out", _apiMethod);
428+
[op cancel];
429+
if (_error != nil) {
430+
_error([NSError errorWithDomain:@"Leanplum" code:1
431+
userInfo:@{NSLocalizedDescriptionKey: @"Request timed out"}]);
432+
}
433+
LP_END_TRY
443434
}
444435
};
445436

437+
// Send. operationBlock will run synchronously.
438+
// Adding to OperationQueue puts it in the background.
446439
if (async) {
447440
[sendNowQueue addOperationWithBlock:operationBlock];
448441
} else {
@@ -729,6 +722,11 @@ + (void)onNoPendingDownloads:(LeanplumVariablesChangedBlock)block
729722
noPendingDownloadsBlock = block;
730723
}
731724

725+
+ (NSOperationQueue *)sendNowQueue
726+
{
727+
return sendNowQueue;
728+
}
729+
732730
@end
733731

734732
@implementation LPResponse

0 commit comments

Comments
 (0)