Skip to content

Commit

Permalink
chore: Add some processRecurrence tracing (#9723)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dschoordsch committed May 7, 2024
1 parent 476b3e5 commit 6c4369d
Showing 1 changed file with 79 additions and 69 deletions.
148 changes: 79 additions & 69 deletions packages/server/graphql/private/mutations/processRecurrence.ts
@@ -1,3 +1,4 @@
import tracer from 'dd-trace'
import ms from 'ms'
import {getJSDateFromRRuleDate, getRRuleDateFromJSDate} from 'parabol-client/shared/rruleUtil'
import {SubscriptionChannel} from 'parabol-client/types/constEnums'
Expand Down Expand Up @@ -129,18 +130,20 @@ const processRecurrence: MutationResolvers['processRecurrence'] = async (_source
.between([false, r.minval], [false, now], {index: 'hasEndedScheduledEndTime'})
.run()

const res = await Promise.all(
meetingsToEnd.map((meeting) => {
if (isMeetingTeamPrompt(meeting)) {
return safeEndTeamPrompt({meeting, now, context, r, subOptions})
} else if (isMeetingRetrospective(meeting)) {
return safeEndRetrospective({meeting, now, context})
} else {
return standardError(new Error('Unhandled recurring meeting type'), {
tags: {meetingId: meeting.id, meetingType: meeting.meetingType}
})
}
})
const res = await tracer.trace('processRecurrence.endMeetings', async () =>
Promise.all(
meetingsToEnd.map((meeting) => {
if (isMeetingTeamPrompt(meeting)) {
return safeEndTeamPrompt({meeting, now, context, r, subOptions})
} else if (isMeetingRetrospective(meeting)) {
return safeEndRetrospective({meeting, now, context})
} else {
return standardError(new Error('Unhandled recurring meeting type'), {
tags: {meetingId: meeting.id, meetingType: meeting.meetingType}
})
}
})
)
)

const meetingsEnded = res.filter((res) => !('error' in res)).length
Expand All @@ -149,64 +152,71 @@ const processRecurrence: MutationResolvers['processRecurrence'] = async (_source

// For each active meeting series, get the meeting start times (according to rrule) after the most
// recent meeting start time and before now.
const activeMeetingSeries = await getActiveMeetingSeries()
await Promise.allSettled(
activeMeetingSeries.map(async (meetingSeries) => {
const seriesTeam = await dataLoader.get('teams').loadNonNull(meetingSeries.teamId)
if (seriesTeam.isArchived || !seriesTeam.isPaid) {
return
}

const [seriesOrg, lastMeeting] = await Promise.all([
dataLoader.get('organizations').load(seriesTeam.orgId),
dataLoader.get('lastMeetingByMeetingSeriesId').load(meetingSeries.id)
])

// remove this check after 2024-05-05
if (
lastMeeting?.meetingSeriesId !== meetingSeries.id ||
lastMeeting.teamId !== meetingSeries.teamId
) {
const error = new Error(
'lastMeetingByMeetingSeriesId returned a meeting that does not match the series'
)
sendToSentry(error)
throw error
}

if (seriesOrg.lockedAt) {
return
}

// For meetings that should still be active, start the meeting and set its end time.
// Any subscriptions are handled by the shared meeting start code
const rrule = RRule.fromString(meetingSeries.recurrenceRule)
// technically, RRULE should never return NaN here but there's a bug in the library
// https://github.com/jakubroztocil/rrule/issues/321
if (isNaN(rrule.options.interval)) {
return
}

// Only get meetings that should currently be active, i.e. meetings that should have started
// within the last 24 hours, started after the last meeting in the series, and started before
// 'now'.
const fromDate = lastMeeting
? new Date(Math.max(lastMeeting.createdAt.getTime() + ms('10m'), now.getTime() - ms('24h')))
: new Date(0)
const newMeetingsStartTimes = rrule.between(
getRRuleDateFromJSDate(fromDate),
getRRuleDateFromJSDate(now)
)
for (const startTime of newMeetingsStartTimes) {
const err = await startRecurringMeeting(
meetingSeries,
getJSDateFromRRuleDate(startTime),
dataLoader,
subOptions
const activeMeetingSeries = await tracer.trace(
'processRecurrence.getActiveMeetingSeries',
getActiveMeetingSeries
)
await tracer.trace('processRecurrence.startActiveMeetingSeries', async () =>
Promise.allSettled(
activeMeetingSeries.map(async (meetingSeries) => {
const seriesTeam = await dataLoader.get('teams').loadNonNull(meetingSeries.teamId)
if (seriesTeam.isArchived || !seriesTeam.isPaid) {
return
}

const [seriesOrg, lastMeeting] = await Promise.all([
dataLoader.get('organizations').load(seriesTeam.orgId),
dataLoader.get('lastMeetingByMeetingSeriesId').load(meetingSeries.id)
])

// remove this check after 2024-05-05
if (
lastMeeting?.meetingSeriesId !== meetingSeries.id ||
lastMeeting.teamId !== meetingSeries.teamId
) {
const error = new Error(
'lastMeetingByMeetingSeriesId returned a meeting that does not match the series'
)
sendToSentry(error)
throw error
}

if (seriesOrg.lockedAt) {
return
}

// For meetings that should still be active, start the meeting and set its end time.
// Any subscriptions are handled by the shared meeting start code
const rrule = RRule.fromString(meetingSeries.recurrenceRule)
// technically, RRULE should never return NaN here but there's a bug in the library
// https://github.com/jakubroztocil/rrule/issues/321
if (isNaN(rrule.options.interval)) {
return
}

// Only get meetings that should currently be active, i.e. meetings that should have started
// within the last 24 hours, started after the last meeting in the series, and started before
// 'now'.
const fromDate = lastMeeting
? new Date(
Math.max(lastMeeting.createdAt.getTime() + ms('10m'), now.getTime() - ms('24h'))
)
: new Date(0)
const newMeetingsStartTimes = rrule.between(
getRRuleDateFromJSDate(fromDate),
getRRuleDateFromJSDate(now)
)
if (!err) meetingsStarted++
}
})
for (const startTime of newMeetingsStartTimes) {
const err = await startRecurringMeeting(
meetingSeries,
getJSDateFromRRuleDate(startTime),
dataLoader,
subOptions
)
if (!err) meetingsStarted++
}
})
)
)

const data = {meetingsStarted, meetingsEnded}
Expand Down

0 comments on commit 6c4369d

Please sign in to comment.