Ensure message sends only succeed or fail once.

// FREEBIE
pull/1/head
Matthew Chen 9 years ago
parent e1439a54dc
commit 3598cc18fa

@ -159,6 +159,7 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4;
@property (nonatomic, readonly) void (^failureHandler)(NSError *_Nonnull error); @property (nonatomic, readonly) void (^failureHandler)(NSError *_Nonnull error);
@property (nonatomic) OWSSendMessageOperationState operationState; @property (nonatomic) OWSSendMessageOperationState operationState;
@property (nonatomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier; @property (nonatomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier;
@property (nonatomic) BOOL hasCompleted;
@end @end
@ -190,6 +191,13 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4;
return; return;
} }
// Ensure we call the success or failure handler exactly once.
@synchronized(strongSelf)
{
OWSCAssert(!strongSelf.hasCompleted);
strongSelf.hasCompleted = YES;
}
[message updateWithMessageState:TSOutgoingMessageStateSentToService]; [message updateWithMessageState:TSOutgoingMessageStateSentToService];
DDLogDebug(@"%@ succeeded.", strongSelf.tag); DDLogDebug(@"%@ succeeded.", strongSelf.tag);
@ -204,6 +212,13 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4;
return; return;
} }
// Ensure we call the success or failure handler exactly once.
@synchronized(strongSelf)
{
OWSCAssert(!strongSelf.hasCompleted);
strongSelf.hasCompleted = YES;
}
[strongSelf.message updateWithSendingError:error]; [strongSelf.message updateWithSendingError:error];
DDLogDebug(@"%@ failed with error: %@", strongSelf.tag, error); DDLogDebug(@"%@ failed with error: %@", strongSelf.tag, error);
@ -281,9 +296,14 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4;
{ {
DDLogDebug(@"%@ remainingRetries: %lu", self.tag, (unsigned long)remainingRetries); DDLogDebug(@"%@ remainingRetries: %lu", self.tag, (unsigned long)remainingRetries);
// Use this flag to ensure a given operation only succeeds or fails once.
__block BOOL onceFlag = NO;
RetryableFailureHandler retryableFailureHandler = ^(NSError *_Nonnull error) { RetryableFailureHandler retryableFailureHandler = ^(NSError *_Nonnull error) {
DDLogInfo(@"%@ Sending failed.", self.tag); DDLogInfo(@"%@ Sending failed.", self.tag);
OWSAssert(!onceFlag);
onceFlag = YES;
if (![error isRetryable] || [error isFatal]) { if (![error isRetryable] || [error isFatal]) {
DDLogInfo(@"%@ Skipping retry due to terminal error: %@", self.tag, error); DDLogInfo(@"%@ Skipping retry due to terminal error: %@", self.tag, error);
self.failureHandler(error); self.failureHandler(error);
@ -299,7 +319,14 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4;
} }
}; };
[self.messageSender attemptToSendMessage:self.message success:self.successHandler failure:retryableFailureHandler]; [self.messageSender attemptToSendMessage:self.message
success:^{
OWSAssert(!onceFlag);
onceFlag = YES;
self.successHandler();
}
failure:retryableFailureHandler];
} }
- (void)markAsComplete - (void)markAsComplete
@ -762,6 +789,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// retryable errors. // retryable errors.
if ([error isFatal]) { if ([error isFatal]) {
failureHandler(error); failureHandler(error);
return;
} }
if ([error isRetryable] && !firstRetryableError) { if ([error isRetryable] && !firstRetryableError) {

Loading…
Cancel
Save