Merge branch 'charlesmchen/messageSendFatalErrors'

This commit is contained in:
Michael Kirk 2017-04-19 18:52:35 -04:00
commit 0bbe73e110
1 changed files with 33 additions and 1 deletions

View File

@ -54,7 +54,12 @@ void AssertIsOnSendingQueue()
static void *kNSError_MessageSender_IsRetryable = &kNSError_MessageSender_IsRetryable;
static void *kNSError_MessageSender_ShouldBeIgnoredForGroups = &kNSError_MessageSender_ShouldBeIgnoredForGroups;
static void *kNSError_MessageSender_IsFatal = &kNSError_MessageSender_IsFatal;
// isRetryable and isFatal are opposites but not redundant.
//
// If a group message send fails, the send will be retried if any of the errors were retryable UNLESS
// any of the errors were fatal. Fatal errors trump retryable errors.
@implementation NSError (OWSMessageSender)
- (BOOL)isRetryable
@ -84,6 +89,19 @@ static void *kNSError_MessageSender_ShouldBeIgnoredForGroups = &kNSError_Message
objc_setAssociatedObject(self, kNSError_MessageSender_ShouldBeIgnoredForGroups, @(value), OBJC_ASSOCIATION_COPY);
}
- (BOOL)isFatal
{
NSNumber *value = objc_getAssociatedObject(self, kNSError_MessageSender_IsFatal);
// This value will NOT always be set for all errors by the time we query it's value.
// Default to NOT fatal.
return value ? [value boolValue] : NO;
}
- (void)setIsFatal:(BOOL)value
{
objc_setAssociatedObject(self, kNSError_MessageSender_IsFatal, @(value), OBJC_ASSOCIATION_COPY);
}
@end
#pragma mark -
@ -266,7 +284,7 @@ NSUInteger const OWSSendMessageOperationMaxRetries = 4;
RetryableFailureHandler retryableFailureHandler = ^(NSError *_Nonnull error) {
DDLogInfo(@"%@ Sending failed.", self.tag);
if (![error isRetryable]) {
if (![error isRetryable] || [error isFatal]) {
DDLogInfo(@"%@ Skipping retry due to terminal error: %@", self.tag, error);
self.failureHandler(error);
return;
@ -748,6 +766,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
id failureResult = groupSendFuture.forceGetFailure;
if ([failureResult isKindOfClass:[NSError class]]) {
NSError *error = failureResult;
// Some errors should be ignored when sending messages
// to groups. See discussion on
// NSError (OWSMessageSender) category.
@ -755,6 +774,15 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
continue;
}
// Some errors should never be retried, in order to avoid
// hitting rate limits, for example. Unfortunately, since
// group send retry is all-or-nothing, we need to fail
// immediately even if some of the other recipients had
// retryable errors.
if ([error isFatal]) {
failureHandler(error);
}
if ([error isRetryable] && !firstRetryableError) {
firstRetryableError = error;
} else if (![error isRetryable] && !firstNonRetryableError) {
@ -859,6 +887,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// Key will continue to be unaccepted, so no need to retry. It'll only cause us to hit the Pre-Key request
// rate limit
[error setIsRetryable:NO];
// Avoid the "Too many failures with this contact" error rate limiting.
[error setIsFatal:YES];
return failureHandler(error);
}
@ -869,6 +899,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// We're already rate-limited. No need to exacerbate the problem.
[error setIsRetryable:NO];
// Avoid exacerbating the rate limiting.
[error setIsFatal:YES];
return failureHandler(error);
}