Backend robustness to email sending or analytics tracking failures (#728)

* Make `sendEmail` functions await email send success

* Make tracking and email sending not throw on failure
This commit is contained in:
Marshall Polaris 2022-08-15 22:13:38 -07:00 committed by GitHub
parent 186befd0ac
commit d00fe7bcd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 29 deletions

View File

@ -3,7 +3,7 @@ import * as Amplitude from '@amplitude/node'
import { DEV_CONFIG } from '../../common/envs/dev' import { DEV_CONFIG } from '../../common/envs/dev'
import { PROD_CONFIG } from '../../common/envs/prod' import { PROD_CONFIG } from '../../common/envs/prod'
import { isProd } from './utils' import { isProd, tryOrLogError } from './utils'
const key = isProd() ? PROD_CONFIG.amplitudeApiKey : DEV_CONFIG.amplitudeApiKey const key = isProd() ? PROD_CONFIG.amplitudeApiKey : DEV_CONFIG.amplitudeApiKey
@ -15,10 +15,12 @@ export const track = async (
eventProperties?: any, eventProperties?: any,
amplitudeProperties?: Partial<Amplitude.Event> amplitudeProperties?: Partial<Amplitude.Event>
) => { ) => {
await amp.logEvent({ return await tryOrLogError(
amp.logEvent({
event_type: eventName, event_type: eventName,
user_id: userId, user_id: userId,
event_properties: eventProperties, event_properties: eventProperties,
...amplitudeProperties, ...amplitudeProperties,
}) })
)
} }

View File

@ -74,9 +74,8 @@ export const sendMarketResolutionEmail = async (
// Modify template here: // Modify template here:
// https://app.mailgun.com/app/sending/domains/mg.manifold.markets/templates/edit/market-resolved/initial // https://app.mailgun.com/app/sending/domains/mg.manifold.markets/templates/edit/market-resolved/initial
// Mailgun username: james@mantic.markets
await sendTemplateEmail( return await sendTemplateEmail(
privateUser.email, privateUser.email,
subject, subject,
'market-resolved', 'market-resolved',
@ -152,7 +151,7 @@ export const sendWelcomeEmail = async (
const emailType = 'generic' const emailType = 'generic'
const unsubscribeLink = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}` const unsubscribeLink = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}`
await sendTemplateEmail( return await sendTemplateEmail(
privateUser.email, privateUser.email,
'Welcome to Manifold Markets!', 'Welcome to Manifold Markets!',
'welcome', 'welcome',
@ -183,7 +182,7 @@ export const sendOneWeekBonusEmail = async (
const emailType = 'generic' const emailType = 'generic'
const unsubscribeLink = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}` const unsubscribeLink = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}`
await sendTemplateEmail( return await sendTemplateEmail(
privateUser.email, privateUser.email,
'Manifold Markets one week anniversary gift', 'Manifold Markets one week anniversary gift',
'one-week', 'one-week',
@ -215,7 +214,7 @@ export const sendThankYouEmail = async (
const emailType = 'generic' const emailType = 'generic'
const unsubscribeLink = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}` const unsubscribeLink = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}`
await sendTemplateEmail( return await sendTemplateEmail(
privateUser.email, privateUser.email,
'Thanks for your Manifold purchase', 'Thanks for your Manifold purchase',
'thank-you', 'thank-you',
@ -250,7 +249,7 @@ export const sendMarketCloseEmail = async (
const emailType = 'market-resolve' const emailType = 'market-resolve'
const unsubscribeUrl = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}` const unsubscribeUrl = `${UNSUBSCRIBE_ENDPOINT}?id=${userId}&type=${emailType}`
await sendTemplateEmail( return await sendTemplateEmail(
privateUser.email, privateUser.email,
'Your market has closed', 'Your market has closed',
'market-close', 'market-close',
@ -309,7 +308,7 @@ export const sendNewCommentEmail = async (
if (contract.outcomeType === 'FREE_RESPONSE' && answerId && answerText) { if (contract.outcomeType === 'FREE_RESPONSE' && answerId && answerText) {
const answerNumber = `#${answerId}` const answerNumber = `#${answerId}`
await sendTemplateEmail( return await sendTemplateEmail(
privateUser.email, privateUser.email,
subject, subject,
'market-answer-comment', 'market-answer-comment',
@ -332,7 +331,7 @@ export const sendNewCommentEmail = async (
bet.outcome bet.outcome
)}` )}`
} }
await sendTemplateEmail( return await sendTemplateEmail(
privateUser.email, privateUser.email,
subject, subject,
'market-comment', 'market-comment',
@ -377,7 +376,7 @@ export const sendNewAnswerEmail = async (
const subject = `New answer on ${question}` const subject = `New answer on ${question}`
const from = `${name} <info@manifold.markets>` const from = `${name} <info@manifold.markets>`
await sendTemplateEmail( return await sendTemplateEmail(
privateUser.email, privateUser.email,
subject, subject,
'market-answer', 'market-answer',

View File

@ -1,11 +1,16 @@
import * as mailgun from 'mailgun-js' import * as mailgun from 'mailgun-js'
import { tryOrLogError } from './utils'
const initMailgun = () => { const initMailgun = () => {
const apiKey = process.env.MAILGUN_KEY as string const apiKey = process.env.MAILGUN_KEY as string
return mailgun({ apiKey, domain: 'mg.manifold.markets' }) return mailgun({ apiKey, domain: 'mg.manifold.markets' })
} }
export const sendTextEmail = (to: string, subject: string, text: string) => { export const sendTextEmail = async (
to: string,
subject: string,
text: string
) => {
const data: mailgun.messages.SendData = { const data: mailgun.messages.SendData = {
from: 'Manifold Markets <info@manifold.markets>', from: 'Manifold Markets <info@manifold.markets>',
to, to,
@ -14,14 +19,15 @@ export const sendTextEmail = (to: string, subject: string, text: string) => {
// Don't rewrite urls in plaintext emails // Don't rewrite urls in plaintext emails
'o:tracking-clicks': 'htmlonly', 'o:tracking-clicks': 'htmlonly',
} }
const mg = initMailgun() const mg = initMailgun().messages()
return mg.messages().send(data, (error) => { const result = await tryOrLogError(mg.send(data))
if (error) console.log('Error sending email', error) if (result != null) {
else console.log('Sent text email', to, subject) console.log('Sent text email', to, subject)
}) }
return result
} }
export const sendTemplateEmail = ( export const sendTemplateEmail = async (
to: string, to: string,
subject: string, subject: string,
templateId: string, templateId: string,
@ -38,10 +44,10 @@ export const sendTemplateEmail = (
'o:tag': templateId, 'o:tag': templateId,
'o:tracking': true, 'o:tracking': true,
} }
const mg = initMailgun() const mg = initMailgun().messages()
const result = await tryOrLogError(mg.send(data))
return mg.messages().send(data, (error) => { if (result != null) {
if (error) console.log('Error sending email', error) console.log('Sent template email', templateId, to, subject)
else console.log('Sent template email', templateId, to, subject) }
}) return result
} }

View File

@ -42,6 +42,15 @@ export const writeAsync = async (
} }
} }
export const tryOrLogError = async <T>(task: Promise<T>) => {
try {
return await task
} catch (e) {
console.error(e)
return null
}
}
export const isProd = () => { export const isProd = () => {
return admin.instanceId().app.options.projectId === 'mantic-markets' return admin.instanceId().app.options.projectId === 'mantic-markets'
} }