#Uploading a File through a Server Action takes forever

59 messages · Page 1 of 1 (latest)

wheat quail
#

I currently port over some code to Nextjs Server Actions. I have a Frontend Form that submits a file, I wanna upload that file to my 3rd party API. But the request takes over 4 Minutes before it probably times out.

export async function uploadDocument(formData: FormData) {
  const projectId = z.string().parse(formData.get("projectId"));
  const file = formData.get("file") as File;

  const bearer = await getBearer();

  try {
    await fetch(
      `https://apiurl.com/Project/${projectId}/container/${file.name}`,
      {
        method: "POST",
        body: formData,
        credentials: "include",
        headers: {
          Authorization: `Bearer ${bearer}`,
        },
      },
    );

    revalidatePath(`/project/${projectId}/documents`);

    return { ok: true };
  } catch (e) {
    console.log(e);
    return { ok: false };
  }
}

I get no errors. Any idea what causes it?

cursive tigerBOT
#

🔎 This post has been indexed in our web forum and will be seen by search engines so other users can find it outside Discord

🕵️ Your user profile is private by default and won't be visible to users outside Discord, if you want to be visible in the web forum you can add the "Public Profile" role in id:customize

✅ You can mark a message as the answer for your post with Right click -> Apps -> Mark Solution
(if you don't see the option, try refreshing Discord with Ctrl + R)

wheat quail
#

Payload is

lyric valve
#

https:apiurl.com isn't a correct url (but i think that isn't the issue)

wheat quail
#

I just replaced the real url in the snippet

#

Corrected it 😅

lyric valve
#

i meant not having :// but i gathered it was fake

#

if on vercel, server actions can only last 10 secs

wheat quail
#

its in dev currently

lyric valve
#

ahh but, 4 mins is decent length

wheat quail
#

its just a 400KB file and in my old remix action handler this was done in like under a second so there must be some issue hidden in the code

#

Only info I get in the console after the thing is finally run is this:

lyric valve
#

you should prob fix the revalidatetags issue (whereever that is)

lyric valve
wheat quail
#

weird thing is I dont even use revalidateTags

#

This appears after exactly 4.0 Minutes, everytime.

#

Response: ```0:["$@1",["development",null]]
1:{"ok":true}

#

Its really weird that it goes through. Let me check in built mode.

lyric valve
#

and your using latest nextjs version right? (edit: i can see it is latest)

wheat quail
#

So in the built verision the same issue appears, I do not have any revalidateTagsin the codebase, I just commented out the revalidatePathsbut it makes no difference.

lyric valve
#

and if you console log before and after the fetch req, how far apart are the logs

wheat quail
#

I just added a console timer, running currently.

#
  console.time("upload");

  console.timeLog("upload", "uploading file");
  try {
    await fetch(
      `https://apiurl.com/Project/${projectId}/container/${file.name}`,
      {
        method: "POST",
        body: formData,
        credentials: "include",
        headers: {
          "Content-Type": "multipart/form-data",
          Authorization: `Bearer ${bearer}`,
        },
      },
    );

    console.timeEnd("upload");
#

upload: 0.036ms uploading file

lyric valve
#

so thats fast

#

try putting the same type of code around other parts of the function (and at the very start and end)

wheat quail
#

just fyi the file never arrives on the server, but for some reason the function still returns the { ok: true } to the frontend after the 4 minutes.

lyric valve
#

if you get the response of the fetch, what do you get?

const res = await fetch()
console.log({status: res.status, msg: res.text()})
wheat quail
#
export async function uploadDocument(formData: FormData) {
  console.time("upload");

  const projectId = z.string().parse(formData.get("projectId"));
  const file = formData.get("file") as File;

  const bearer = await getBearer();

  console.timeLog("upload", "got auth token");
  try {
    const res = await fetch(
      `https://apiurl.net/Project/${projectId}/container/${file.name}`,
      {
        method: "POST",
        body: formData,
        credentials: "include",
        headers: {
          "Content-Type": "multipart/form-data",
          Authorization: `Bearer ${bearer}`,
        },
      },
    );

    console.log({ status: res.status, msg: res.text() });

    console.timeLog("upload", "file ulpaded");

    return { ok: true };
  } catch (e) {
    console.timeLog("upload", "arrived in the catch");
    console.log(e);
    return { ok: false };
  } finally {
    console.timeEnd("upload");
  }
}
#

Running right now.

#

upload: 2.328ms got auth token

#

after the 4 mins are passed I will try to send the body explicitly instead of just passing the formdata from the payload.

#

maybe that will work.

lyric valve
#

this is weird... also the finally might not be run because you return (but idk fully about that)

wheat quail
#

so I just get back a 408error

#

as the response status

lyric valve
#

as in your server action didn't respond?

#

or the fetch req

wheat quail
#

fetch req

lyric valve
#

and how long did the fetch req take?

wheat quail
#

it always takes 4.0 then it timeouts.

#

minutes

lyric valve
#

as that sounds like an issue with the 3rd party (as nextjs fetch isn't that bad i didn't think...)

wheat quail
lyric valve
#

ohh

wheat quail
#

yes I also though that, but I have the working remix app on my machine as well, and this is the code from the remix action: ```ts
const file = formData.get("file") as File;
const filename = file.name;

const response = await fetch(
  `https://apiurl..../Project/${projectId}/container/${filename}`,
  {
    method: "POST",
    body: formData,
    credentials: "include",
    headers: getAuthHeader(context),
  },
);

if (!response.ok) {
  throw response;
}
lyric valve
#

also shouldn't you create a buffer from formdata to send?

wheat quail
#

So it makes no sense to me why the fetch behaves so strange

lyric valve
#

the only diference i can see is: "Content-Type": "multipart/form-data", but im guessing getAuthHeader creates it

wheat quail
#

Ahh... I dont find any reason

#

I will set up a reproducable example and create an issue. In the meantime I will just call it from the client side.

#

Its the only file upload I have in the application currently.

#

Just need to find an api to demonstrate the upload on D:

lyric valve
#

this is partly why i use https://uploadthing.com/ now, because i don't need to worry about all this forwarding of files (not trying to advertise, just mentioning how i got around needing to deal with it)

wheat quail
#

now from the client it works seemlessly, must be some form of fetch passing the file

#

that makes this behaviour