From 616b721183e5d771de1911c27d6aa1842c2af55b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=B6rdle=20Bot?= Date: Fri, 21 Nov 2025 16:18:26 +0100 Subject: [PATCH] feat: improve daily puzzle generation with a global Prisma client, detailed logging, and race condition handling. --- app/page.tsx | 56 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/app/page.tsx b/app/page.tsx index aea074e..cc3dee1 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,41 +1,59 @@ import Game from '@/components/Game'; +import { PrismaClient } from '@prisma/client'; + +// PrismaClient is attached to the `global` object in development to prevent +// exhausting your database connection limit. +const globalForPrisma = global as unknown as { prisma: PrismaClient }; + +const prisma = globalForPrisma.prisma || new PrismaClient(); + +if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma; + async function getDailyPuzzle() { try { - // In a real app, use absolute URL or internal API call - // Since we are server-side, we can call the DB directly or fetch the API - // Calling API requires full URL (http://localhost:3000...), which is tricky in some envs - // Better to call DB directly here or use a helper function shared with the API - // But for simplicity, let's fetch the API if we can, or just use Prisma directly. - // Using Prisma directly is better for Server Components. - - const { PrismaClient } = await import('@prisma/client'); - const prisma = new PrismaClient(); - const today = new Date().toISOString().split('T')[0]; + console.log(`[getDailyPuzzle] Checking puzzle for date: ${today}`); + let dailyPuzzle = await prisma.dailyPuzzle.findUnique({ where: { date: today }, include: { song: true }, }); if (!dailyPuzzle) { - // Trigger generation logic (same as API) - // Duplicating logic is bad, but for now it's quickest. - // Ideally extract "getOrCreateDailyPuzzle" to a lib. + console.log('[getDailyPuzzle] No puzzle found, attempting to create...'); const songsCount = await prisma.song.count(); + console.log(`[getDailyPuzzle] Found ${songsCount} songs in DB`); + if (songsCount > 0) { const skip = Math.floor(Math.random() * songsCount); const randomSong = await prisma.song.findFirst({ skip }); + if (randomSong) { - dailyPuzzle = await prisma.dailyPuzzle.create({ - data: { date: today, songId: randomSong.id }, - include: { song: true }, - }); + try { + dailyPuzzle = await prisma.dailyPuzzle.create({ + data: { date: today, songId: randomSong.id }, + include: { song: true }, + }); + console.log(`[getDailyPuzzle] Created puzzle for song: ${randomSong.title}`); + } catch (createError) { + // Handle race condition: if another request created it in the meantime + console.log('[getDailyPuzzle] Creation failed, trying to fetch again (likely race condition)'); + dailyPuzzle = await prisma.dailyPuzzle.findUnique({ + where: { date: today }, + include: { song: true }, + }); + } } + } else { + console.log('[getDailyPuzzle] No songs available to create puzzle'); } } - if (!dailyPuzzle) return null; + if (!dailyPuzzle) { + console.log('[getDailyPuzzle] Failed to get or create puzzle'); + return null; + } return { id: dailyPuzzle.id, @@ -46,7 +64,7 @@ async function getDailyPuzzle() { coverImage: dailyPuzzle.song.coverImage ? `/uploads/covers/${dailyPuzzle.song.coverImage}` : null, }; } catch (e) { - console.error(e); + console.error('[getDailyPuzzle] Error:', e); return null; } }