从Next.js API路由(应用路由器)内分发非阻塞获取请求

kx5bkwkv  于 2023-11-18  发布在  其他
关注(0)|答案(1)|浏览(106)

我试图从Next.js 13(App Router)的API路由中发出一个fetch请求。我不想阻止该请求,因为我只是简单地调度它,然后继续前进。然而,当我不阻止fetch请求时,它不会触发,但当我在请求的开头放置“await”时,它会触发。
我正在运行一个托管在Vercel上的Next.js 13(应用路由器)项目。
我没有在其他地方找到任何关于这个的讨论,所以希望有人能在这里提供一些见解。这是我的函数(请注意这是在异步POST路由中):

export default async function generateEmbeddingsForPDF(
    workspaceDataSource: WorkspaceFile, 
    supabase: SupabaseClient<Database, 'public'>,
    request: NextRequest
): Promise<boolean>
{
    const { data, error } = await supabase
    .storage.from('workspace-files')
    .download(workspaceDataSource.filePath);

    if (error && !data)
    {
        console.error('ERROR Downloading File::', error);
        return false;
    }

    try
    {
        const pdfLoader = new PDFLoader(data);
        const pageContentList = (await pdfLoader.loadAndSplit()).map(page => page.pageContent);
        const chunkSplitSize = 50;

        for (let i = 0; i < pageContentList.length; i += chunkSplitSize)
        {
            try
            {
                const chunks = pageContentList.slice(i, i + chunkSplitSize);
                const url = `${request.nextUrl.origin}/api-v1/workspaces/generate-embeddings/ingestor`;
                console.log('INGESTOR URL::', url);

                // This does not work unless I put an await at the start. 
                axios.post(url, {
                    workspaceFile: workspaceDataSource,
                    textChunks: chunks,
                    totalChunks: pageContentList.length,
                }, {
                    headers: {
                        cookie: request.headers.get('cookie'),
                        'Content-Type': 'application/json',
                    }
                });

            }
            catch (error)
            {
                console.error('ERROR WITH EMBEDDINGS DISPATCHER::', error);
            }
        }
    }
    catch (error)
    {
        console.error('Error splitting pdf into pages::', error);
        return false;
    }

    return true;
}

字符串
要运行它,我所要做的就是发布到/api-v1/workspace/generate-embeddings。
同样,这在我的开发环境中也有效,但在生产环境中无效,所以如果Vercel不允许同源获取请求有什么奇怪的地方,请给我解释一下:D
我之所以这样做是因为我想让用户知道进程已经开始,尽快返回原始的API路由。此外,通过将工作负载划分为分段部分,这意味着我可以避免由于Vercel的5分钟功能限制而导致的超时(有些PDF需要10-15分钟才能连续完成)。

9nvpjoqh

9nvpjoqh1#

好了,这个问题的解决方案是,正如Chris汉密尔顿所指出的,axios/fetch请求在它还没有发出之前就被拆除了。我怀疑调度fetch请求所涉及的延迟大于请求的持续时间,所以我把它们放在一个promise数组中,然后在这里等待所有的请求。请记住,我的代码并不关心这些promise发生了什么,他们都被派出去了
以下是我在返回之前放入的内容,以便阻止:

try
{
    const pdfLoader = new PDFLoader(data);
    const pageContentList = (await pdfLoader.loadAndSplit()).map(page => page.pageContent);
    const chunkSplitSize = 50;

    const promises: AxiosPromise[] = [];

    for (let i = 0; i < pageContentList.length; i += chunkSplitSize)
    {
        try
        {
            const chunks = pageContentList.slice(i, i + chunkSplitSize);
            const url = `${request.nextUrl.origin}/api-v1/workspaces/generate-embeddings/ingestor`;
            console.log('INGESTOR URL::', url);

            // This does not work unless I put an await at the start. 
            const embeddingPromise = axios.post(url, {
                workspaceFile: workspaceDataSource,
                textChunks: chunks,
                totalChunks: pageContentList.length,
            }, {
                headers: {
                    cookie: request.headers.get('cookie'),
                    'Content-Type': 'application/json',
                }
            });

            promises.push(embeddingPromise);

        }
        catch (error)
        {
            console.error('ERROR WITH EMBEDDINGS DISPATCHER::', error);
        }
    }

    await Promise.all(promises);
}
catch (error)
{
    console.error('Error splitting pdf into pages::', error);
    return false;
}

return true;

字符串

相关问题