Hey, the website I made was showcased on a twitch stream, which caused a sudden traffic spike of approximately 200-400 users. I'm on a hobby plan, and I treat this project as a learning playground to figure out all things vercel. The logs show errors seen in the image below, I can't find any information on the topic and would love to find out more, as I'd love to prevent that in the future - if possible.

Some things that came to my mind are that the page on initial load performs 6 fetches (100 users each) to the twitch.tv API to grab viewer count info. Perhaps it's hitting a rate limit, but I can't know for sure - couldn't reproduce it locally.
If I understood and implemented caching correctly, it shouldn't be an issue as I want to keep the response in cache for 5 minutes, but perhaps I'm not understanding something very simple here - I'm a newbie to the more 'backend' parts of the framework.
I'll attach the /streamers route contents below:
import db from '@/lib/db';import { streamers } from '@/lib/schema';import { NextResponse } from 'next/server';import { getTwitchToken } from '../utils';
async function validateToken(token: string) { const response = await fetch('https://id.twitch.tv/oauth2/validate', { headers: { Authorization: `OAuth ${token}`, }, });
if (!response.ok) { console.error('Token validation failed:', await response.text()); return false; }
return true;}
async function fetchStreamerBatch(usernames: string[], initialToken: string) { let token = initialToken; const isValid = await validateToken(token); if (!isValid) { console.log('Token invalid, attempting to get new token...'); token = await getTwitchToken(); if (!token) { throw new Error( 'Failed to get new Twitch token after validation failure' ); } }
const queryString = usernames.map((name) => `user_login=${name}`).join('&');
console.log( `Attempting Twitch API call with token: ${token.substring(0, 10)}...` );
const response = await fetch( `https://api.twitch.tv/helix/streams?${queryString}`, { headers: { 'Client-ID': process.env.TWITCH_CLIENT_ID!, Authorization: `Bearer ${token}`, }, cache: 'no-store', } );
if (!response.ok) { const errorText = await response.text(); throw new Error( `Twitch API error: ${response.status} - ${errorText}. Client ID: ${process.env.TWITCH_CLIENT_ID?.substring(0, 5)}...` ); }
return (await response.json()).data;}
export async function GET(request: Request) { try { const [allStreamers, token] = await Promise.all([ db .select({ id: streamers.id, name: streamers.name, twitchUrl: streamers.twitchUrl, isSweat: streamers.isSweat, avatarUrl: streamers.avatarUrl, }) .from(streamers), getTwitchToken(), ]);
if (!token) { console.error('Token retrieval failed'); throw new Error( 'Failed to get Twitch token - token is null or undefined' ); }
const usernames = allStreamers .map((streamer) => streamer.twitchUrl?.split('/').pop()) .filter((username): username is string => !!username);
const OPTIMIZED_BATCH_SIZE = 100; const batchPromises = Array.from( { length: Math.ceil(usernames.length / OPTIMIZED_BATCH_SIZE) }, (_, i) => { const start = i * OPTIMIZED_BATCH_SIZE; const batchUsernames = usernames.slice( start, start + OPTIMIZED_BATCH_SIZE ); return fetchStreamerBatch(batchUsernames, token); } );
const streamDataArrays = await Promise.all(batchPromises); const streamData = streamDataArrays.flat();
const streamDataMap = new Map( streamData.map((stream) => [stream.user_login.toLowerCase(), stream]) );
const liveStreamers = allStreamers .map((streamer) => { if (!streamer.twitchUrl) { return null; }
const twitchUsername = streamer.twitchUrl .split('/') .pop() ?.toLowerCase(); if (!twitchUsername) { return null; }
const twitchData = streamDataMap.get(twitchUsername); if (!twitchData) { return null; }
return { id: streamer.id, name: streamer.name, twitchUrl: streamer.twitchUrl, isSweat: streamer.isSweat, avatarUrl: streamer.avatarUrl, viewerCount: twitchData.viewer_count, live: twitchData.type === 'live', gameName: twitchData.game_name, }; }) .filter( (streamer): streamer is NonNullable<typeof streamer> => streamer !== null );
return NextResponse.json(liveStreamers, { headers: { 'Cache-Control': 'public, s-maxage=300, stale-while-revalidate=60', }, }); } catch (error) { console.error('Detailed error in streamer fetch:', error); return NextResponse.json( { error: error instanceof Error ? error.message : 'Failed to fetch streamer status', }, { status: 500 } ); }}Thanks for any help in advance!