signal-desktop/ts/jobs/helpers/handleMultipleSendErrors.ts

84 lines
2.4 KiB
TypeScript
Raw Normal View History

2022-01-12 00:50:11 +00:00
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { LoggerType } from '../../types/Logging';
import * as Errors from '../../types/errors';
import { sleepForRateLimitRetryAfterTime } from './sleepForRateLimitRetryAfterTime';
2022-01-12 00:50:11 +00:00
import { getHttpErrorCode } from './getHttpErrorCode';
import { strictAssert } from '../../util/assert';
import { findRetryAfterTimeFromError } from './findRetryAfterTimeFromError';
2022-02-16 18:36:21 +00:00
import { SendMessageProtoError } from '../../textsecure/Errors';
2022-01-12 00:50:11 +00:00
2022-02-16 18:36:21 +00:00
export function maybeExpandErrors(error: unknown): ReadonlyArray<unknown> {
if (error instanceof SendMessageProtoError) {
return error.errors || [error];
}
return [error];
}
// Note: toThrow is very important to preserve the full error for outer handlers. For
// example, the catch handler check for Safety Number Errors in conversationJobQueue.
2022-01-12 00:50:11 +00:00
export async function handleMultipleSendErrors({
errors,
isFinalAttempt,
log,
markFailed,
timeRemaining,
2022-02-16 18:36:21 +00:00
toThrow,
2022-01-12 00:50:11 +00:00
}: Readonly<{
errors: ReadonlyArray<unknown>;
isFinalAttempt: boolean;
log: Pick<LoggerType, 'info'>;
markFailed?: (() => void) | (() => Promise<void>);
2022-01-12 00:50:11 +00:00
timeRemaining: number;
2022-02-16 18:36:21 +00:00
toThrow: unknown;
2022-01-12 00:50:11 +00:00
}>): Promise<void> {
strictAssert(errors.length, 'Expected at least one error');
const formattedErrors: Array<string> = [];
let retryAfterError: unknown;
let longestRetryAfterTime = -Infinity;
let serverAskedUsToStop = false;
errors.forEach(error => {
formattedErrors.push(Errors.toLogFormat(error));
const errorCode = getHttpErrorCode(error);
if (errorCode === 413 || errorCode === 429) {
2022-01-12 00:50:11 +00:00
const retryAfterTime = findRetryAfterTimeFromError(error);
if (retryAfterTime > longestRetryAfterTime) {
retryAfterError = error;
longestRetryAfterTime = retryAfterTime;
}
} else if (errorCode === 508 || errorCode === 400) {
2022-01-12 00:50:11 +00:00
serverAskedUsToStop = true;
}
});
log.info(
`${formattedErrors.length} send error(s): ${formattedErrors.join(',')}`
);
if (isFinalAttempt || serverAskedUsToStop) {
await markFailed?.();
2022-01-12 00:50:11 +00:00
}
if (serverAskedUsToStop) {
log.info('server responded with 508 or 400. Giving up on this job');
2022-01-12 00:50:11 +00:00
return;
}
if (retryAfterError && !isFinalAttempt) {
await sleepForRateLimitRetryAfterTime({
2022-01-12 00:50:11 +00:00
err: retryAfterError,
log,
timeRemaining,
});
}
2022-02-16 18:36:21 +00:00
throw toThrow;
2022-01-12 00:50:11 +00:00
}