Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions apps/backend/src/app/api/latest/internal/metrics/route.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type DataPoints = yup.InferType<typeof DataPointsSchema>;

const METRICS_CACHE_NAMESPACE = "metrics";
const ONE_HOUR_MS = 60 * 60 * 1000;
const MAX_USERS_FOR_COUNTRY_SAMPLE = 10_000;

async function withMetricsCache<T>(tenancy: Tenancy, suffix: string, prisma: PrismaClientTransaction, includeAnonymous: boolean = false, loader: () => Promise<T>): Promise<T> {
return await getOrSetCacheValue<T>({
Expand All @@ -32,12 +33,20 @@ const DataPointsSchema = yupArray(yupObject({


async function loadUsersByCountry(tenancy: Tenancy, prisma: PrismaClientTransaction, includeAnonymous: boolean = false): Promise<Record<string, number>> {
const totalUsers = await prisma.projectUser.count({
where: {
tenancyId: tenancy.id,
...(includeAnonymous ? {} : { isAnonymous: false }),
},
});
const users = await prisma.projectUser.findMany({
where: {
tenancyId: tenancy.id,
...(includeAnonymous ? {} : { isAnonymous: false }),
},
select: { projectUserId: true },
orderBy: { projectUserId: "asc" },
take: Math.min(totalUsers, MAX_USERS_FOR_COUNTRY_SAMPLE),
});

if (users.length === 0) {
Expand All @@ -46,6 +55,7 @@ async function loadUsersByCountry(tenancy: Tenancy, prisma: PrismaClientTransact

const userIds = users.map((user) => user.projectUserId);
const userIdArray = Prisma.sql`ARRAY[${Prisma.join(userIds.map((id) => Prisma.sql`${id}`))}]::text[]`;
const scalingFactor = totalUsers > users.length ? totalUsers / users.length : 1;

const rows = await globalPrismaClient.$queryRaw<{ countryCode: string | null, userCount: bigint }[]>(Prisma.sql`
WITH latest_ip AS (
Expand All @@ -70,8 +80,15 @@ async function loadUsersByCountry(tenancy: Tenancy, prisma: PrismaClientTransact
`);

return Object.fromEntries(
rows.map(({ userCount, countryCode }) => [countryCode, Number(userCount)])
.filter(([countryCode]) => countryCode)
rows.map(({ userCount, countryCode }) => {
if (!countryCode) {
return null;
}
const count = Number(userCount);
const estimatedCount = scalingFactor === 1 ? count : Math.round(count * scalingFactor);
return [countryCode, estimatedCount] as [string, number];
})
.filter((entry): entry is [string, number] => entry !== null)
);
}

Expand Down