diff --git a/package.json b/package.json index 4d916aa9..bc06c2f8 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "private": true, "scripts": { - "dev": "next dev", + "dev": "node server.js", "build": "next build", "start": "next start", "lint": "next lint", diff --git a/server.js b/server.js new file mode 100644 index 00000000..cfa096b1 --- /dev/null +++ b/server.js @@ -0,0 +1,30 @@ +// Custom Next.js server with extended timeout for video generation +// Node.js default server.requestTimeout is 5 minutes (300,000ms) +// We extend it to 10 minutes for long-running fal.ai video generation + +const { createServer } = require('http'); +const next = require('next'); + +const dev = process.env.NODE_ENV !== 'production'; +const hostname = 'localhost'; +const port = process.env.PORT || 3000; + +const app = next({ dev, hostname, port }); +const handle = app.getRequestHandler(); + +app.prepare().then(() => { + const server = createServer(async (req, res) => { + // Use WHATWG URL API instead of deprecated url.parse() + const parsedUrl = new URL(req.url, `http://${hostname}:${port}`); + await handle(req, res, parsedUrl); + }); + + // Increase timeout to 10 minutes for long-running video generation + server.requestTimeout = 600000; // 10 minutes + server.headersTimeout = 610000; // Slightly longer than requestTimeout + + server.listen(port, () => { + console.log(`> Ready on http://${hostname}:${port}`); + console.log(`> Server timeout set to ${server.requestTimeout / 1000 / 60} minutes`); + }); +}); diff --git a/src/app/api/generate/route.ts b/src/app/api/generate/route.ts index fe5c3418..ae8f34b4 100644 --- a/src/app/api/generate/route.ts +++ b/src/app/api/generate/route.ts @@ -1,10 +1,23 @@ +/** + * Generate API Route + * + * TIMEOUT CONFIGURATION: + * - maxDuration: Only applies on Vercel, not locally + * - AbortSignal.timeout: Controls outgoing fetch to providers + * - For local development, server.requestTimeout must be set in server.js (Node.js default is 5 minutes) + * + * FAL.AI QUEUE API NOTE: + * The generateWithFalQueue function exists but is NOT used because fal.ai's queue API + * has file size limitations that are too restrictive for our use case. We use the blocking + * fal.run endpoint instead, which requires the server timeout to be extended for video generation. + */ import { NextRequest, NextResponse } from "next/server"; import { GoogleGenAI } from "@google/genai"; import { GenerateRequest, GenerateResponse, ModelType, SelectedModel, ProviderType } from "@/types"; import { GenerationInput, GenerationOutput, ProviderModel } from "@/lib/providers/types"; import { uploadImageForUrl, shouldUseImageUrl, deleteImages } from "@/lib/images"; -export const maxDuration = 600; // 10 minute timeout for video generation +export const maxDuration = 600; // 10 minute timeout for video generation (Vercel only) export const dynamic = 'force-dynamic'; // Ensure this route is always dynamic // Map model types to Gemini model IDs @@ -889,7 +902,11 @@ async function generateWithFal( /** * Generate video using fal.ai Queue API * Uses async queue submission + polling to handle long-running video generation - * that would otherwise timeout with the blocking fal.run endpoint + * that would otherwise timeout with the blocking fal.run endpoint. + * + * NOTE: This function is NOT currently used because fal.ai's queue API has file size + * limitations that are too restrictive. We use the blocking fal.run endpoint instead + * with an extended server timeout configured in server.js. */ async function generateWithFalQueue( requestId: string,