Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

run / wait can get stuck when using Next.js with App Router #136

Closed
mattt opened this issue Sep 18, 2023 · 9 comments · Fixed by #264
Closed

run / wait can get stuck when using Next.js with App Router #136

mattt opened this issue Sep 18, 2023 · 9 comments · Fixed by #264

Comments

@mattt
Copy link
Member

mattt commented Sep 18, 2023

At yesterday's hackathon, a participant shared that predictions created and polled for completion using run would hang indefinitely, despite the Replicate dashboard showing that prediction as finishing minutes earlier.

After debugging by adding a console.log statement in the progress callback function, we determined that this behavior was caused by the extensions to fetch made by Next.js when using App Router 1. From "Data Fetching, Caching, and Revalidating" in the Next.js docs:

Next.js extends the native fetch Web API to allow you to configure the caching and revalidating behavior for each fetch request on the server. React extends fetch to automatically memoize fetch requests while rendering a React component tree.
...
By default, Next.js automatically caches the returned values of fetch in the Data Cache on the server. This means that the data can be fetched at build time or request time, cached, and reused on each data request.

Because the initial GET /v1/predictions/{id} response was cached, subsequent requests polling for status returned the same response, which had the initial "starting" status.

Our workaround involved setting replicate.fetch to a wrapped function that specified a cache: no-store fetch option. But it's unclear whether there's a better way to get the desired behavior.

We should either document or add a workaround to make this work correctly in Next.js.

Footnotes

  1. fetch when using Pages Router, like in the "Build a website with Next.js" sample project, works as expected.

@mirko314
Copy link

mirko314 commented Sep 20, 2023

Hey,
I also just ran into this, and it took me quite some time to debug and come to the conclusion that some "magical" caching must be the culprit.

Would you mind to share your workaround code?

With App Router and Vercel getting even more traction, this definatly should be addressed!

Thanks!

@mattt
Copy link
Member Author

mattt commented Sep 20, 2023

@mirko314 Thanks for sharing. That's a helpful data point.

Here's what I remember the code to be. Please give this a try and let me know if that works for you:

replicate = new Replicate({/*...*/})
replicate.fetch = (url, options) => {
  return fetch(url, { ...options, cache: "no-store" });
};

@mirko314
Copy link

Thanks @mattt, that worked well!

@Autometrique
Copy link

@mattt @mirko314
Hi!
Thanks for this very helpful comment.
I ran into this too. I'm fairly new to next.js with the app router and having a hard time trying to make it work.
Maybe would you have a more complete exemple to share, showing how you managed to make it work?

I'm trying to use it within a replicate create/wait structure (which is equivalent to run/wait)

That would be fantastic :-)

I agree this should be addressed. We won't be the only ones trying to use replicate on the new next.js app router.

Thanks!

@pondorasti
Copy link

pondorasti commented Oct 1, 2023

Just ran into the same issue and this #136 (comment) fixed it for me too. Thanks for the post @mattt, probably saved me hours of troubleshooting 🙌

@Autometrique
Copy link

@mattt Would it be possible to update the documentation with a more detailed explanation on how to use replicate-javascript on next.js recent versions? 😃

@leerob
Copy link

leerob commented Dec 8, 2023

Rather than changing the Replicate fetch behavior, you can use noStore to opt-out of caching for your component.

import Replicate from 'replicate';
import { unstable_noStore as noStore } from 'next/cache';

let replicate = new Replicate(...);
 
export default async function Component() {
  noStore();
  let prediction = await replicate.predictions.create(...)
  ...
}

API: https://nextjs.org/docs/app/api-reference/functions/unstable_noStore

@zeke
Copy link
Member

zeke commented May 23, 2024

I've opened a couple PRs to help prevent further confusion about this:

@wuyasong
Copy link

您无需改变复制fetch行为,就可以选择noStore退出组件的缓存。

import Replicate from 'replicate';
import { unstable_noStore as noStore } from 'next/cache';

let replicate = new Replicate(...);
 
export default async function Component() {
  noStore();
  let prediction = await replicate.predictions.create(...)
  ...
}

API:https://nextjs.org/docs/app/api-reference/functions/unstable_noStore

This Great, I was stuck with this issue for a day, and after reading this issue, it was finally fixed

@zeke zeke closed this as completed in #264 May 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants