perf : better concurrent handle
CI / Verify (push) Successful in 1m29s
CI / Build immutable images and deploy (push) Successful in 1m48s

This commit is contained in:
2026-09-10 19:08:25 +07:00 Unverified
parent 00f59e6e85
commit 89be58c517
7 changed files with 59 additions and 19 deletions
+44 -14
View File
@@ -33,6 +33,28 @@ import type { PosterBlendMode } from "@/components/public/material-poster";
const catalogVersionSchema = z.object({ version: z.string() });
const posterBlendModes = new Set(["normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"]);
// Leave most of the per-pod pool available to other visitors during cache misses.
const PUBLIC_QUERY_CONCURRENCY = 3;
async function runWithConcurrency<
const T extends ReadonlyArray<() => Promise<unknown>>,
>(
tasks: T,
concurrency = PUBLIC_QUERY_CONCURRENCY,
): Promise<{ [K in keyof T]: Awaited<ReturnType<T[K]>> }> {
const results = new Array<unknown>(tasks.length);
let next = 0;
await Promise.all(
Array.from({ length: Math.min(concurrency, tasks.length) }, async () => {
while (next < tasks.length) {
const index = next++;
results[index] = await tasks[index]();
}
}),
);
return results as { [K in keyof T]: Awaited<ReturnType<T[K]>> };
}
function catalogCharacterWithUrls(
item: typeof catalogCharacters.$inferSelect,
materialByKey = new Map<string, typeof catalogMaterials.$inferSelect>(),
@@ -221,7 +243,11 @@ export async function listPublicGuideCards() {
.from(guides)
.innerJoin(media, eq(media.id, guides.coverMediaId))
.where(and(eq(guides.isPublic, true), isNull(guides.trashedAt)))
.orderBy(desc(guides.sortOrder), desc(guides.createdAt), asc(guides.name)), getDb().select().from(glossaryAliases)]);
.orderBy(desc(guides.sortOrder), desc(guides.createdAt), asc(guides.name)), getDb().select({
kind: glossaryAliases.kind,
catalogKey: glossaryAliases.catalogKey,
alias: glossaryAliases.alias,
}).from(glossaryAliases)]);
const grouped = aliasesByItem(aliases);
return rows.map(({ coverObjectKey, ...guide }) => ({
...guide,
@@ -303,22 +329,26 @@ async function getGuideContent(slug: string, publicOnly: boolean) {
const materialKeys = [...new Set(
[...row.character.ascension, ...row.character.leveling].flatMap((group) => group.items.map((item) => item.key)),
)];
const [sections, weaponConditionsRows, groups, profile, constellationGroups, teamConditionRows, teams, aliases, materials, poster, bleeding] = await Promise.all([
getDb().select().from(guideSections).where(and(eq(guideSections.guideId, row.guide.id), eq(guideSections.enabled, true))).orderBy(asc(guideSections.sortOrder)),
getDb().select().from(weaponConditions).where(eq(weaponConditions.guideId, row.guide.id)).orderBy(asc(weaponConditions.sortOrder)),
getDb().select().from(artifactGroups).where(eq(artifactGroups.guideId, row.guide.id)).orderBy(asc(artifactGroups.sortOrder)),
getDb().select().from(artifactProfiles).where(eq(artifactProfiles.guideId, row.guide.id)).limit(1),
getDb().select().from(constellationConditions).where(eq(constellationConditions.guideId, row.guide.id)).orderBy(asc(constellationConditions.sortOrder)),
getDb().select().from(teamConditions).where(eq(teamConditions.guideId, row.guide.id)).orderBy(asc(teamConditions.sortOrder)),
getDb().select().from(teamCompositions).where(eq(teamCompositions.guideId, row.guide.id)).orderBy(asc(teamCompositions.sortOrder)),
getDb().select().from(glossaryAliases),
materialKeys.length
const [sections, weaponConditionsRows, groups, profile, constellationGroups, teamConditionRows, teams, aliases, materials, poster, bleeding] = await runWithConcurrency([
() => getDb().select().from(guideSections).where(and(eq(guideSections.guideId, row.guide.id), eq(guideSections.enabled, true))).orderBy(asc(guideSections.sortOrder)),
() => getDb().select().from(weaponConditions).where(eq(weaponConditions.guideId, row.guide.id)).orderBy(asc(weaponConditions.sortOrder)),
() => getDb().select().from(artifactGroups).where(eq(artifactGroups.guideId, row.guide.id)).orderBy(asc(artifactGroups.sortOrder)),
() => getDb().select().from(artifactProfiles).where(eq(artifactProfiles.guideId, row.guide.id)).limit(1),
() => getDb().select().from(constellationConditions).where(eq(constellationConditions.guideId, row.guide.id)).orderBy(asc(constellationConditions.sortOrder)),
() => getDb().select().from(teamConditions).where(eq(teamConditions.guideId, row.guide.id)).orderBy(asc(teamConditions.sortOrder)),
() => getDb().select().from(teamCompositions).where(eq(teamCompositions.guideId, row.guide.id)).orderBy(asc(teamCompositions.sortOrder)),
() => getDb().select({
kind: glossaryAliases.kind,
catalogKey: glossaryAliases.catalogKey,
alias: glossaryAliases.alias,
}).from(glossaryAliases),
() => materialKeys.length
? getDb().select().from(catalogMaterials).where(inArray(catalogMaterials.key, materialKeys))
: [],
row.guide.posterArtMediaId
: Promise.resolve([]),
() => row.guide.posterArtMediaId
? getDb().select().from(media).where(eq(media.id, row.guide.posterArtMediaId)).limit(1)
: Promise.resolve([]),
getDb().select({ layer: guidePosterBleeding, asset: media }).from(guidePosterBleeding).leftJoin(media, eq(media.id, guidePosterBleeding.mediaId)).where(eq(guidePosterBleeding.guideId, row.guide.id)).orderBy(asc(guidePosterBleeding.sortOrder)),
() => getDb().select({ layer: guidePosterBleeding, asset: media }).from(guidePosterBleeding).leftJoin(media, eq(media.id, guidePosterBleeding.mediaId)).where(eq(guidePosterBleeding.guideId, row.guide.id)).orderBy(asc(guidePosterBleeding.sortOrder)),
]);
const groupedAliases = aliasesByItem(aliases);
const materialByKey = new Map(materials.map((item) => [item.key, item]));