From 5c5756c4729c979bc0ba35cab3d3d7369f5d8080 Mon Sep 17 00:00:00 2001 From: Barry Chen Date: Tue, 12 Nov 2024 08:15:42 -0600 Subject: [PATCH] chore(scripts): add option for perf stats on inactive uids script --- .../get-inactive-account-uids.ts | 129 ++++++++++++++---- 1 file changed, 104 insertions(+), 25 deletions(-) diff --git a/packages/fxa-auth-server/scripts/delete-inactive-accounts/get-inactive-account-uids.ts b/packages/fxa-auth-server/scripts/delete-inactive-accounts/get-inactive-account-uids.ts index 9e9e0e66291..5825e9663dd 100755 --- a/packages/fxa-auth-server/scripts/delete-inactive-accounts/get-inactive-account-uids.ts +++ b/packages/fxa-auth-server/scripts/delete-inactive-accounts/get-inactive-account-uids.ts @@ -13,6 +13,7 @@ import fs from 'fs'; import os from 'os'; +import { performance } from 'perf_hooks'; import { Command } from 'commander'; import { StatsD } from 'hot-shots'; @@ -47,6 +48,22 @@ import { const createFilepath = (endDate: Date) => `inactive-account-uids-${endDate.toISOString().substring(0, 10)}.csv`; +const _collectPerfStatsOn = (statsMap: Map) => { + const sm = statsMap; + + return ReturnType>(name: string, fn: T) => { + const stats: number[] = []; + sm.set(name, stats); + + return async (...args: Parameters) => { + const start = performance.now(); + const result = await fn(...args); + stats.push(performance.now() - start); + return result; + }; + }; +}; + const init = async () => { const program = new Command(); program @@ -89,7 +106,8 @@ const init = async () => { '--results-limit [number]', 'The number of results per accounts DB query. Defaults to 100000.', parseInt - ); + ) + .option('--perf-stats [true|false]', 'Print out performance stats.', false); program.parse(process.argv); @@ -102,6 +120,10 @@ const init = async () => { program.activeByDate || endDate ).valueOf(); const filepath = program.outputPath || createFilepath(endDate); + const perfStats = program.perfStats ? new Map() : null; + const collectPerfStatsOn = perfStats + ? _collectPerfStatsOn(perfStats) + : ReturnType>(_, fn: T) => fn; const config = appConfig.getProperties(); const log = initLog({ @@ -150,9 +172,33 @@ const init = async () => { const refreshTokensFn = oauthDb.getRefreshTokensByUid.bind(oauthDb); const accessTokensFn = oauthDb.getAccessTokensByUid.bind(oauthDb); + const checkActiveSessionToken = collectPerfStatsOn( + 'Session Token Check', + async (uid: string, activeByDateTimestamp: number) => + await hasActiveSessionToken(sessionTokensFn, uid, activeByDateTimestamp) + ); + const checkRefreshToken = collectPerfStatsOn( + 'Refresh Token Check', + async (uid: string, activeByDateTimestamp: number) => + await hasActiveRefreshToken(refreshTokensFn, uid, activeByDateTimestamp) + ); + const checkAccessToken = collectPerfStatsOn( + 'Access Token Check', + async (uid: string) => await hasAccessToken(accessTokensFn, uid) + ); + + const getPlaySubscriptionsCollection = collectPerfStatsOn( + 'Get Play Collection', + async () => await playBilling.purchaseDbRef().get() + ); + const getAppleSubscriptionsCollection = collectPerfStatsOn( + 'Get Apple Collection', + async () => await appleIap.purchasesDbRef().get() + ); + const iapSubUids = new Set(); - const playSubscriptionsCollection = await playBilling.purchaseDbRef().get(); - const appleSubscriptionsCollection = await appleIap.purchasesDbRef().get(); + const playSubscriptionsCollection = await getPlaySubscriptionsCollection(); + const appleSubscriptionsCollection = await getAppleSubscriptionsCollection(); ((collections) => { for (const c of collections) { for (const purchaseRecordSnapshot of c.docs) { @@ -164,28 +210,37 @@ const init = async () => { } })([playSubscriptionsCollection, appleSubscriptionsCollection]); - const hasIapSubscription = async (accountRecord: Account) => - iapSubUids.has(accountRecord.uid) && - ((await playSubscriptions.getSubscriptions(accountRecord.uid)).length > 0 || - (await appStoreSubscriptions.getSubscriptions(accountRecord.uid)).length > - 0); - - const isActive = async (accountRecord: Account) => { - return ( - (await hasActiveSessionToken( - sessionTokensFn, - accountRecord.uid, - activeByDateTimestamp - )) || - (await hasActiveRefreshToken( - refreshTokensFn, - accountRecord.uid, - activeByDateTimestamp - )) || - (await hasAccessToken(accessTokensFn, accountRecord.uid)) || - (await hasIapSubscription(accountRecord)) - ); - }; + const getPlaySubscriptions = collectPerfStatsOn( + 'Get Play Subscriptions', + async (uid: string) => await playSubscriptions.getSubscriptions(uid) + ); + const getAppleSubscriptions = collectPerfStatsOn( + 'Get Apple Subscriptions', + async (uid: string) => await appStoreSubscriptions.getSubscriptions(uid) + ); + + const hasIapSubscription = collectPerfStatsOn( + 'Has IAP Check', + async (accountRecord: Account) => + iapSubUids.has(accountRecord.uid) && + ((await getPlaySubscriptions(accountRecord.uid)).length > 0 || + (await getAppleSubscriptions(accountRecord.uid)).length > 0) + ); + + const isActive = collectPerfStatsOn( + 'Active Status Check', + async (accountRecord: Account) => { + return ( + (await checkActiveSessionToken( + accountRecord.uid, + activeByDateTimestamp + )) || + (await checkRefreshToken(accountRecord.uid, activeByDateTimestamp)) || + (await checkAccessToken(accountRecord.uid)) || + (await hasIapSubscription(accountRecord)) + ); + } + ); if (isDryRun) { const countQuery = accountWhereAndOrderBy().count({ @@ -249,6 +304,30 @@ const init = async () => { console.log(`Number of inactive accounts: ${totalInactiveAccounts}`); console.log(`Inactive account UIDs written to: ${filepath}`); + if (perfStats) { + const stats = {}; + + perfStats.forEach((xs, k) => { + const cols = {}; + const sorted = xs.sort((a, b) => a - b); + cols['Total Calls'] = sorted.length; + cols['Duration (ms)'] = sorted.reduce((a, b) => a + b, 0); + cols['Avg'] = + sorted.length === 0 ? 0 : cols['Duration (ms)'] / cols['Total Calls']; + cols['Median'] = + sorted.length === 0 + ? 0 + : sorted.length % 2 === 0 + ? (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2 + : sorted[Math.floor(sorted.length / 2)]; + + stats[k] = cols; + }); + + console.log('Performance Stats:'); + console.table(stats); + } + return 0; };