Server actions taking too long to start executing... ?
Unanswered
Cape lion posted this in #help-forum
Cape lionOP
Hi All,
I'm using NextJS 14 in dev mode, I'm noticing that when I call a react server action, it executes slowly.
I traced this to about a 250-300msec delay from when the function is invoked in my client component until the function begins executing....
In my client component....
In my server action...
I'm using RSC for rendering all my entry pages and want to mutate that data using server actions with revalidation...
Is this just due to it being used in dev mode ?
Or is this lag an inherent issue with server actions ?
Thanks!
I'm using NextJS 14 in dev mode, I'm noticing that when I call a react server action, it executes slowly.
I traced this to about a 250-300msec delay from when the function is invoked in my client component until the function begins executing....
In my client component....
import { updateFilename } from '@/actions'
// ...
const handleBlur = async () {
const tstart = Date.now();
await updateFilename({ file_id, name: e.target.value, go: tstart })
const tend = Date.now()
console.log(tend-tstart) // this takes about 500 msec.
}In my server action...
export async function updateFilename({ file_id, name, go }) {
const tstart = Date.now()
console.log(tstart-go) // THIS IS A GOOD 250-300 MSEC
// access database...
// mutate data
// revalidate path
}I'm using RSC for rendering all my entry pages and want to mutate that data using server actions with revalidation...
Is this just due to it being used in dev mode ?
Or is this lag an inherent issue with server actions ?
Thanks!
8 Replies
I'm suspecting it's something to do with how you're accessing the database.
@Marchy I'm suspecting it's something to do with how you're accessing the database.
Cape lionOP
Hi, the full server action '@/actions/index.js' is as follows. I'm only initializing the database client after the function is invoked, and so I had thought this was not the reason for the delay.
'use server'
import { revalidatePath, revalidateTag } from 'next/cache'
import { auth } from '@clerk/nextjs';
import { neon, neonConfig } from '@neondatabase/serverless';
neonConfig.fetchConnectionCache = true;
import { drizzle } from 'drizzle-orm/neon-http';
import { and, eq } from 'drizzle-orm';
import { file } from '@/drizzle/schema';
export async function updateFilename({ file_id, name, go }) {
try {
const tstart = Date.now()
console.log(tstart-go)
// Authenticate
const { sessionClaims } = auth()
const owner_id = sessionClaims?.user_id;
var tend = Date.now()
// Validate
if(!file_id || !name) return { isError: true, message: 'Failed to update' }
if(name.length>255) return { isError: true, message: 'Name cannot exceed 255 characters' }
const client = neon(process.env.NEON_DB_URL)
const db = drizzle(client);
tend = Date.now()
const res = await db.update(file).set({ name }).where(and(
eq(file.id, file_id),
eq(file.owner_id, owner_id),
)).returning()
console.log(res)
revalidatePath(`/docs/folders/${file_id}`)
revalidatePath(`/docs/files/${file_id}`)
tend = Date.now()
console.log('Completed in', tend-tstart, 'msec')
return { isSuccess: true, data: res }
}
catch (e) {
console.log(e)
return { isError: true, message: 'Failed to update' }
}
}Ah, yeah. You shouldn't need to create a new client/connection for every server action.
There's an example here
https://github.com/vercel/examples/blob/main/storage/postgres-drizzle/lib/drizzle.ts
There's an example here
https://github.com/vercel/examples/blob/main/storage/postgres-drizzle/lib/drizzle.ts
There's also a guide here for Prisma - drizzle should be similar with using globalThis
https://www.prisma.io/docs/guides/other/troubleshooting-orm/help-articles/nextjs-prisma-client-dev-practices
https://www.prisma.io/docs/guides/other/troubleshooting-orm/help-articles/nextjs-prisma-client-dev-practices
Cape lionOP
I tried that but without success. It seems more to do with the time it takes the browser to take the formData and submit the form. Here is a barebones example where I only record the time the button is clicked in the frontend and the time recorded by the server action.
Client code is...
and the server action is...
Client code is...
"use client"
import { myAction } from "@/actions";
function TestForm() {
return (
<form action={myAction}>
<button type="submit" onClick={()=>console.log(Date.now())}>Test...</button>
</form>
)
}
export default TestForm and the server action is...
export async function myAction(prevState, formData) {
const now = Date.now()
console.log(now)
return true
}@Cape lion I tried that but without success. It seems more to do with the time it takes the browser to take the formData and submit the form. Here is a barebones example where I only record the time the button is clicked in the frontend and the time recorded by the server action.
Client code is...
"use client"
import { myAction } from "@/actions";
function TestForm() {
return (
<form action={myAction}>
<button type="submit" onClick={()=>console.log(Date.now())}>Test...</button>
</form>
)
}
export default TestForm
and the server action is...
export async function myAction(prevState, formData) {
const now = Date.now()
console.log(now)
return true
}
Hmm, I can't seem to replicate with this. It loads instantly for me.
What is { prevState, formData }?
What is { prevState, formData }?
Are you trying to update state from your server action?
Cape lionOP
Thanks Marchy, I got it to work as expected after starting a new Next project. Before, I had only upgraded to 14 (from 13.5x). I see now that also the server actions are logging to the browser console instead of the terminal.