batch identity key emails

This commit is contained in:
miloschwartz
2026-08-18 15:59:51 -04:00
parent 809bc662e0
commit bdd7f40688
2 changed files with 24 additions and 13 deletions
+14 -2
View File
@@ -7,6 +7,18 @@ import VirtualApiKeyGenerated from "@server/emails/templates/VirtualApiKeyGenera
import { formatVirtualApiKeyCredential } from "@server/lib/virtualApiKey";
const EMAIL_GATEWAY_URL_LIMIT = 5;
const VIRTUAL_API_KEY_EMAIL_BATCH_SIZE = 50;
export async function mapInBatches<T>(
items: T[],
fn: (item: T) => Promise<void>,
batchSize = VIRTUAL_API_KEY_EMAIL_BATCH_SIZE
): Promise<void> {
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
await Promise.all(batch.map(fn));
}
}
async function listVirtualApiKeyGatewayUrls(params: {
orgId: string;
@@ -161,7 +173,7 @@ export async function sendVirtualApiKeyEmails(params: {
? `Your identity key for ${params.orgName}`
: `Virtual API key for ${params.orgName}`;
for (const to of params.recipients) {
await mapInBatches(params.recipients, async (to) => {
await sendEmail(
params.isIdentityKey
? IdentityApiKeyGenerated({
@@ -184,5 +196,5 @@ export async function sendVirtualApiKeyEmails(params: {
subject
}
);
}
});
}
@@ -12,7 +12,8 @@ import config from "@server/lib/config";
import { getOrCreateUserVirtualApiKey } from "@server/lib/virtualApiKey";
import {
sendVirtualApiKeyEmails,
listOrgInferenceGatewayUrls
listOrgInferenceGatewayUrls,
mapInBatches
} from "@server/lib/sendVirtualApiKeyEmail";
import type { EmailIdentityKeysResponse } from "@server/routers/virtualApiKey/types";
import rateLimit, { ipKeyGenerator } from "express-rate-limit";
@@ -218,15 +219,13 @@ export async function emailIdentityKeys(
const orgName = org?.name || orgId;
const gatewayUrls = await listOrgInferenceGatewayUrls(orgId);
const recipients = members.flatMap(({ user }) =>
user.email ? [{ user, email: user.email }] : []
);
let sent = 0;
let skipped = 0;
for (const { user } of members) {
if (!user.email) {
skipped += 1;
continue;
}
const skipped = members.length - recipients.length;
await mapInBatches(recipients, async ({ user, email }) => {
const { key, secret } = await getOrCreateUserVirtualApiKey({
orgId,
user,
@@ -234,7 +233,7 @@ export async function emailIdentityKeys(
});
await sendVirtualApiKeyEmails({
recipients: [user.email],
recipients: [email],
orgName,
orgId,
keyName: key.name,
@@ -242,11 +241,11 @@ export async function emailIdentityKeys(
secret,
allResources: true,
isIdentityKey: true,
accountLabel: user.email || user.name || user.username,
accountLabel: email,
gatewayUrls
});
sent += 1;
}
});
return response<EmailIdentityKeysResponse>(res, {
data: { sent, skipped },