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

Parallel server action calls #69265

Open
yonatanlavy opened this issue Aug 24, 2024 · 10 comments
Open

Parallel server action calls #69265

yonatanlavy opened this issue Aug 24, 2024 · 10 comments
Labels
bug Issue was opened via the bug report template. create-next-app Related to our CLI tool for quickly starting a new Next.js application. linear: next Confirmed issue that is tracked by the Next.js team. Parallel & Intercepting Routes Related to Parallel and/or Intercepting routes. Performance Anything with regards to Next.js performance.

Comments

@yonatanlavy
Copy link

yonatanlavy commented Aug 24, 2024

Link to the code that reproduces this issue

https://github.com/yehonatanyosefi/parallel-routes-example

To Reproduce

  1. start the application
  2. click start button
  3. see console logs come out as ABAB on the server side with two post requests, and on the client side it taking 2 seconds instead of one even though using promise.all

Current vs. Expected behavior

Current behavior of nextjs server actions are they are executed in sequential fashion, however there is no flag or option or a config to let them be executed in parallel. Causing them to block some ux. For example for ai image generation, you'd have to wait for the last call to finish before making your next one, causing you to need to wait over 15 seconds before you can even generate more images instead of the Expected behavior of being able to send them in parallel and stream in finished generations by awaiting them.

In the example I sent you can see even though I used Promise.all on 2 promises that each take a second that should be expected take only 1 second together but because of the sequential nature the current behavior is it takes 2.

Provide environment information

when hosted on vercel it happens, locally it happens too:
Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Pro
  Available memory (MB): 32393
  Available CPU cores: 20
Binaries:
  Node: 20.10.0
  npm: N/A
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 15.0.0-canary.128 // Latest available version is detected (15.0.0-canary.128).
  eslint-config-next: N/A
  react: 19.0.0-rc-eb3ad065-20240822
  react-dom: 19.0.0-rc-eb3ad065-20240822
  typescript: 5.3.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

create-next-app, Parallel & Intercepting Routes, Performance

Which stage(s) are affected? (Select all that apply)

next dev (local), Vercel (Deployed)

Additional context

Edit: https://x.com/cramforce/status/1733240566954230063
Above's link to a reply by Vercel's CTO agreeing it should have control if we want it parallel

@yonatanlavy yonatanlavy added the bug Issue was opened via the bug report template. label Aug 24, 2024
@github-actions github-actions bot added create-next-app Related to our CLI tool for quickly starting a new Next.js application. Parallel & Intercepting Routes Related to Parallel and/or Intercepting routes. Performance Anything with regards to Next.js performance. labels Aug 24, 2024
@simonri
Copy link
Contributor

simonri commented Aug 25, 2024

Server Actions are designed for mutations that update server-side state; they are not recommended for data fetching. Accordingly, frameworks implementing Server Actions typically process one action at a time and do not have a way to cache the return value.

https://react.dev/reference/rsc/use-server#caveats

@yonatanlavy
Copy link
Author

Server Actions are designed for mutations that update server-side state; they are not recommended for data fetching. Accordingly, frameworks implementing Server Actions typically process one action at a time and do not have a way to cache the return value.

https://react.dev/reference/rsc/use-server#caveats

https://x.com/cramforce/status/1733240566954230063
Your CTO agrees with me

@simonri
Copy link
Contributor

simonri commented Aug 25, 2024

The docs mention that only sequential server action calls are supported, so running them in parallel shouldn't be expected.

@musjj
Copy link

musjj commented Aug 27, 2024

I would also agree that it would be very cool to use server actions as an RPC system.

There's this other thread: #69265 that mentions:

I can confirm this is by design.

Why? To prevent things such as inconsistent states from navigation aborting, client fetching, etc.

But I'm not exactly sure what this means. If a server action is pure (only queries for data), there shouldn't be a problem right? If so, it would be nice if there is a way to mark a server action as a "query" and allow it to run parallel to other queries.

@erikslatter
Copy link

I've been using server actions for queries and it's been a great experience having type safety between frontend and backend, but the sequential nature of them is starting to get slowwww. Would love an option to run them in parallel. Has anyone heard news on this since the CTO's tweet in December 2023?

@johnmangan
Copy link

Similarly, we've used Server Actions for data fetching due to their RPC nature w/ built-in type-safety.

Additional advantages over standard Route Handlers is abstraction away some of the code organization decisions. We don't have to place the Route Handler's route.ts file in a specific place nor consider the endpoint route/path we need to fetch to call it. We don't have to rethink route-based middleware auth and permissions for the call the way we do with adding a new route.ts file. Server Actions take on the same permissions as the page that calls them. Simple.

I think there's definitely a place for full Route Handlers. I also can concede that there is other functionality that benefits from sequential execution of Server Actions, which some projects may want to keep.

It would be nice, however, to either tag a Server Action to not run sequentially or to create a new feature in NextJS with similar syntax to Server Actions but runs in parallel the way Route Handlers do (without requiring all the boilerplate code & code organization that Route Handlers require). Even if this new feature doesn't support the existing features that require Server Actions to remain sequentially executed.

Aside: For my team's use-case, I could even understand a decision to limit it to just GET requests, as opposed to Server Action POST requests, and say it can be used for data fetching and is not suggested for mutations. Basically the opposite of intended use for Server Actions, while maintaining the simplicity and elegant DX of Server Actions.

@nikshepsvn
Copy link

yes please +1, make this an option or configurable if the default is supposed to be sequential, will be a huge boost to application experience and DX

@github-actions github-actions bot added the linear: next Confirmed issue that is tracked by the Next.js team. label Nov 11, 2024
@icflorescu
Copy link

I found a solution to this annoying problem and managed to pack it in a little utility:
icflorescu/next-server-actions-parallel, if you're looking for a ready-made solution.
Have a look at the repo, the idea simple enough that you can simply copy-paste it in your own projects if you don't want to add it as a dependency.

@guseggert
Copy link

I workaround this by returning an obj with a promise (similar to @icflorescu). Like in my server action, I return { promise: (async () => { ... } )() }, and the action returns immediately and the promise can be awaited on the client side like await (await serverAction()).promise. Ugly but it works for concurrent server actions.

I think the real problem here is the DX for route handlers is not great, and lots of users see Server Actions as a way to escape that pain w/o using heavyweight frameworks like tRPC. That's probably the real fix here.

@tydt-nals
Copy link

I workaround this by returning an obj with a promise (similar to @icflorescu). Like in my server action, I return { promise: (async () => { ... } )() }, and the action returns immediately and the promise can be awaited on the client side like await (await serverAction()).promise. Ugly but it works for concurrent server actions.

I think the real problem here is the DX for route handlers is not great, and lots of users see Server Actions as a way to escape that pain w/o using heavyweight frameworks like tRPC. That's probably the real fix here.

await (await serverAction()).promise

Thank you for the above suggestion, but if serverAction uses redirect("/some-route") (from next/navigation), an error will occur: Error: NEXT_REDIRECT.
Since redirection happens in a server component, you should move it to the finally block.
Do you have any ideas to fix this error? Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue was opened via the bug report template. create-next-app Related to our CLI tool for quickly starting a new Next.js application. linear: next Confirmed issue that is tracked by the Next.js team. Parallel & Intercepting Routes Related to Parallel and/or Intercepting routes. Performance Anything with regards to Next.js performance.
Projects
None yet
Development

No branches or pull requests

9 participants