Skip to content

Commit 25ce6ec

Browse files
committed
refactor: remove low-level email retry
Spending too much time on retries in the low level email sending clogs the email-queue-step. This can lead to cascading delays if there is an outage with our sender provider. This will cause a vercel runtime failure. Removing the retry logic also obviates the need for separate funcs.
1 parent d0f799c commit 25ce6ec

1 file changed

Lines changed: 17 additions & 60 deletions

File tree

apps/backend/src/lib/emails-low-level.tsx

Lines changed: 17 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,23 @@ export async function lowLevelSendEmailDirectWithoutRetries(options: LowLevelSen
203203
canRetry: boolean,
204204
message?: string,
205205
}>> {
206-
return await _lowLevelSendEmailWithoutRetries(options);
206+
if (!options.to) {
207+
throw new StackAssertionError("No recipient email address provided to sendEmail", omit(options, ['emailConfig']));
208+
}
209+
210+
const result = await _lowLevelSendEmailWithoutRetries(options);
211+
212+
if (result.status === 'error') {
213+
console.warn("Failed to send email.", {
214+
host: options.emailConfig.host,
215+
from: options.emailConfig.senderEmail,
216+
to: options.to,
217+
subject: options.subject,
218+
error: result.error,
219+
}, result.error.rawError);
220+
}
221+
222+
return result;
207223
}
208224

209225
// currently unused, although in the future we may want to use this to minimize the number of requests to Resend
@@ -244,62 +260,3 @@ export async function lowLevelSendEmailResendBatchedDirect(resendApiKey: string,
244260
return result;
245261
}
246262

247-
export async function lowLevelSendEmailDirectViaProvider(options: LowLevelSendEmailOptions): Promise<Result<undefined, {
248-
rawError: any,
249-
errorType: string,
250-
canRetry: boolean,
251-
message?: string,
252-
}>> {
253-
if (!options.to) {
254-
throw new StackAssertionError("No recipient email address provided to sendEmail", omit(options, ['emailConfig']));
255-
}
256-
257-
class DoNotRetryError extends Error {
258-
constructor(public readonly errorObj: {
259-
rawError: any,
260-
errorType: string,
261-
canRetry: boolean,
262-
message?: string,
263-
}) {
264-
super("This error should never be caught anywhere else but inside the lowLevelSendEmailDirectViaProvider function, something went wrong if you see this!");
265-
}
266-
}
267-
268-
let result;
269-
try {
270-
result = await Result.retry(async (attempt) => {
271-
const result = await lowLevelSendEmailDirectWithoutRetries(options);
272-
273-
if (result.status === 'error') {
274-
const extraData = {
275-
host: options.emailConfig.host,
276-
from: options.emailConfig.senderEmail,
277-
to: options.to,
278-
subject: options.subject,
279-
error: result.error,
280-
};
281-
282-
if (result.error.canRetry) {
283-
console.warn("Failed to send email, but error is possibly transient so retrying.", extraData, result.error.rawError);
284-
return Result.error(result.error);
285-
}
286-
287-
console.warn("Failed to send email, and error is not transient, so not retrying.", extraData, result.error.rawError);
288-
throw new DoNotRetryError(result.error);
289-
}
290-
291-
return result;
292-
}, 3, { exponentialDelayBase: 2000 });
293-
} catch (error) {
294-
if (error instanceof DoNotRetryError) {
295-
return Result.error(error.errorObj);
296-
}
297-
throw error;
298-
}
299-
300-
if (result.status === 'error') {
301-
console.warn("Failed to send email after all retries!", result.error);
302-
return Result.error(result.error.errors[0]);
303-
}
304-
return Result.ok(undefined);
305-
}

0 commit comments

Comments
 (0)