Getting a 504/502 error on api requests in Nextjs deployed on Vercel
Asked Answered
P

12

27

I have developed an application in Next.js. For the backend I have used the api endpoints configured in Nextjs which rest inside pages/api. The api end points quite often return 502(Gateway timeout error) or 504(There is a problem with our deployment).

With some research I found out that it was happening because the server was timing out. For Vercel where I have deployed my Nextjs application, the timeout max period for serverless functions is 10s.

The code for one of endpoints(https://bulkbays.com/api/fetchSections) is

import db from "../../config/db";
import Section from "../../Models/Section";

db();

export default async function handler(req, res) {

    console.log('Entered the serverless function')

    Section.find()
        .lean()
        .then((sections) => {
            console.log('Fetched Sections',sections)
            return res.json(sections);
        })
        .catch((err) => {
            console.log('Error in fetching sessions',err)
            return res.json({
                status: false,
                msg: "An unexpected problem occured",
                err,
            });
        });
}

Please someone tell me how could it take more than 10 seconds. Its the simplest of queries one could make. Also the result of this query is just an array of length 9 with objects as items which has strings as its values. It looks sth like this

[
  {
  "_id":"6092a55478ccc2092c5e41b0",
  "images":["http://res.cloudinary.com/bulkbays97/image/upload/v1620223428/eysvsch2hf4ymajizzcn.jpg","http://res.cloudinary.com/bulkbays97/image/upload/v1620223429/qiwa2idfrntiygsfmnx2.jpg","http://res.cloudinary.com/bulkbays97/image/upload/v1620223429/elwhjk7abwcde7ccqcxf.jpg","http://res.cloudinary.com/bulkbays97/image/upload/v1620223428/yuzhe8iehcyj1rmfyr09.jpg"],
  "title":"P-Caps",
  "createdAt":"2021-05-05T14:01:56.626Z",
  "updatedAt":"2021-05-05T14:01:56.626Z","__v":0
  },
  ....
]

This is the log for one of the requests which sent a 502 or 504 response

[GET] /api/fetchSections
14:36:34:38
Status:-1
Duration:10010.32 ms
Init Duration: N/A
Memory Used:60 MB
ID:x7lh8-1620552994128-a44f049a01ae
User Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0
2021-05-09T09:36:44.511Z 62c16977-9c5c-42f5-961f-a63083638a9c Task timed out after 10.01 seconds

Please guide me regarding this. What should I do? Should I use something like Heroku(not serverless) for this or what?

I made this website for a client and now I do not know what is the problem thats causing this.

Princeling answered 9/5, 2021 at 11:4 Comment(5)
Would you mind contacting Vercel support? Please provide information like: what type of database are you using? Where is it hosted? What region? Thank you! vercel.com/contactColloidal
@Colloidal Yup. I did email them. One email came from some technical suppport person where he said that I checked the endpoint and it returned the json data but I told him that this timeout thing does not happen everytime but sometimes. No reply since thenPrinceling
@UsmanAbdurRehman: my guess is faulty connection to mongo server or mongo server configuration, try moving your database to some reliable location (like mongodb atlas) and check if that resolves the issueConidium
In this example from Next.js for Mongoose, they've called the db connection function inside the api handler function. See if that works for you.Ewart
@Conidium I have deployed my db on atlas. I dont know where else to deploy it lolPrinceling
K
30

When using Vercel with a Hobby plan, your serverless API routes can only be processed for 5 seconds. This means that after 5 seconds, the route responds with a 504 GATEWAY TIMEOUT error.

To resolve this, you would need to reduce the amount of time your API route takes to respond, or upgrade your Vercel plan.

Katabasis answered 15/3, 2022 at 15:42 Comment(7)
Do you have any source about this?Greff
@Greff vercel.com/docs/concepts/limits/overviewIllyrian
I am also having 504 all the time, but my local host does not need 5 seconds to respond.Sessler
5 seconds limit doesn't apply to your localhostKatabasis
Mind that if you decide to upgrade your Vercel plan, you must redeploy your project for this to take effect.Gasiform
@AlešOskarKocur comment should be upvoted!Kallman
But before going into pro plan just because someone on stackoverflow said that, check timeout limit here: vercel.com/docs/functions/serverless-functions/…Houk
T
14

I faced the same issue of

Task timed out after 10.01 seconds

with Next.js API endpoints that connect to MongoDB(atlas). The root cause for me is actually that the network access in MongoDB was set to my own IP address and hence disallowed from my deployed application. For those who are facing the same issues with Next.js functions, please also check that MongoDB is configured correctly to accept connections from IP addresses other than your own IP.

See below for context:

NOTE: Vercel uses dynamic IP addresses so you'll need to add an exception to access from any IP address in your MongoDB Atlas dashboard. To do this simplify navigate to the Network Access tab, hit the Add IP Address button, and then hit the Allow Access From Anywhere button or for the Access List Entry enter 0.0.0/0.

Tankage answered 12/1, 2022 at 0:17 Comment(3)
That wasnt the problem in my case btw. I had the IP whitelisting configured for any IP as you have mentioned above. It just happened because the free tier of netlify/vercel or any serverless service doesn't provide a large timeout time for API requests so it is kind of bound to happen if you are querying a database and that too in my case from a shared cluster.Princeling
🙏 Thanks! It works by allowings access from anywhere on mondoDBResumption
Here is Mongodb Integration with Vercel doc mongodb.com/docs/atlas/reference/partner-integrations/vercel/…).Sixty
V
6

Try and isolate the source of the issue first, so you know what steps to take next.

For example, try returning some dummy data without using or connecting to the DB.


export default async function handler(req, res) {

    console.log('Entered the serverless function')

    return { "dummy": "data"}
}

If you still have timeout issues, you now know it's probably because of your Vercel NextJS setup.

If your NextJS setup is not the problem, then you know the issue is caused by your DB. Either the problem is in the query itself, or in the connection.

I'm not sure what DB you're using (I assume it's MongoDB from the syntax).

Most likely possible solutions:

  • It's not very clear what db() does or what it is. I assume it handles connection to the MongoDB instance. Either way, make sure to check if the db() function is asynchronous or not. It's a common mistake; If the function is async and you don't call it properly, then it's possible that the timeout is caused by this asynchronous issue.
  • Do you create new connections for each request or do you reuse existing open connections? Creating a new connection every time can be expensive; It's possible that that's what causes your timeout issue.

If these don't work, try the below:

  • How is your DB hosted? Is it managed by Vercel? Try using another manager to see if that is where the issue resides.
  • Is everything setup correctly in your Vercel dashboard? Make sure you have the correct MongoDB connection string, and that your MongoDB instance is set up to accept connections from your app.
Verdaverdant answered 14/5, 2021 at 9:10 Comment(4)
I am using mongodb hosted on mongodb atlas. I dont know where else to deploy it for free.Princeling
This is the db function. Nextjs hasnt got a way of persisting a db connection throughout all the endpoints so found this way in an article import * as mongoose from 'mongoose' const connection = {}; async function db() { if (connection.isConnected) { return; } const db = await mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true, }); connection.isConnected = db.connections[0].readyState; } export default db;Princeling
This just checks if there already is a connection with the db. if there is, then it returns. Else it establishes a connection with the dbPrinceling
why don't you wait for db function to establish connection. I mean db function returns a promise, you should do "await db()" inside the handler function and then run your mongo query.Yuen
P
2

What I did as a result of constant research was that I posted the API on Heroku and the frontend on Vercel. I read this suggestion in one stackoverflow post from a guy who said that he worked in Vercel and this was the most suitable solution for this.

I think this is a problem with the serverless architecture itself. I tried deploying Nextjs on netlify and faced a similar situation.

Princeling answered 18/5, 2021 at 9:28 Comment(0)
B
1

I had the same issue, it is caused by next-auth(in my case). So the problem was with te versions over 4.15.0 . I set the next-auth version to 4.15.0 it solved the problem for me. Hope it's save some hours for someone.

Blossomblot answered 5/3, 2023 at 17:23 Comment(0)
P
1

If you have env variables that you used for your API you should add them to your vercel project. Here's the source: Vercel Environment Variables

.env file:

MONGODB_URI: "uri-value-here";

Your vercel:

environment variable settings image

This fixed my issue.

Petunia answered 23/6 at 22:42 Comment(0)
G
1

I was struggling with this issue on a personal project for longer than I care to admit. I have 10+ pages/api routes. I forgot to import and add the await connectDb() to all routes. My routes are called in succession frequently, in development all were 200, but in production, some were 200, and others were 504ing with Vercel's FUNCTION_INVOCATION_ERROR (or whatever it's called) indicating the timeout happened in Vercel's edge function in service of the API route (apologies if my terminology isn't completely correct but it's something to that affect). Apparently in development if you don't connect every API route to MongoDB on every call it won't error, the connection must be constant or shared in a different manner, but in production the connection needs to be remade for each route. Leaving this here in case this saves anyone else time.

Gabie answered 29/7 at 0:51 Comment(1)
That's exactly the issue I was facing, thank you!!!Backsaw
H
0

I just encountered this issue as well and managed to solve it.

I was using getStaticProps & getStaticPaths in my page component which works well in development but as soon as I try to deploy in production, there was the invalid json response body error.

Turns out that the getStaticProps & getStaticPaths functions are not establishing a connection to my MongoDB and hence returning undefined which crashed the app.

Solution:

I fixed it by directly connecting to my MongoDB and executing the DB calls from within the getStaticProps & getStaticPaths functions.

Hope this helps someone.

Hispanic answered 12/10, 2022 at 4:43 Comment(0)
A
0

I faced similar issue with typegraphql api and mongodb atlas setup. First if someone is struggling with the configuration of vercel I am pasting my vercel.json

{
  "version": 2,
  "builds": [
    {
      "src": "build/server.js",
      "use": "@vercel/node",
      "config": {
        "includeFiles": [
          "build/**"
        ]
      }
    }
  ],
  "routes": [
    {
      "src": "/(.*)",
      "dest": "/build/server.js"
    }
  ]
}

In my case I had an issue of sequence. All I had to do is to change the order. First await for mongo connection, then await for the server

import { ApolloServer } from '@apollo/server'
import { expressMiddleware } from '@apollo/server/express4'
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer'
import express from 'express'
import http from 'http'
import cors from 'cors'
import bodyParser from 'body-parser'
import { getSchema } from './schema'
// import geoip from 'geoip-lite'
import MobileDetect from 'mobile-detect'
import dotenv from 'dotenv'
import { Context } from './types/context'
import { connectToMongo } from './mongo'
import { getUserFromRequest } from './utils/token'

dotenv.config()

const graphQlPath = process.env.GRAPHQL_PATH

//TODO: check i18next-fs-backend
async function startApolloServer() {
// Required logic for integrating with Express
  const app = express()
  // Our httpServer handles incoming requests to our Express app.
  // Below, we tell Apollo Server to "drain" this httpServer,
  // enabling our servers to shut down gracefully.
  const httpServer = http.createServer(app)

  // Same ApolloServer initialization as before, plus the drain plugin
  // for our httpServer.

  const schema = await getSchema()
  const server = new ApolloServer({
    schema,
    plugins: [
      ApolloServerPluginDrainHttpServer({ httpServer }),
    ],
    introspection: true,

  })

  await server.start()

  app.use(
    graphQlPath,
    cors({
      origin: '*',
    }),
    bodyParser.json(),
    expressMiddleware(server, {
      context: async ({ req }) => {
        const ip = (req.headers['x-forwarded-for'] || req.socket.remoteAddress) as string
        const user = getUserFromRequest(req)
        const context: Context = {
          req,
          user,
          ip,
          // location: geoip.lookup(ip),
          location: null,
          md: new MobileDetect(req.headers['user-agent']),
        }
        return context
      },
    }),

  )

  await connectToMongo()
  const port = process.env.PORT || 4000
  await new Promise<void>((resolve) => httpServer.listen({ port }, resolve))
  console.log(`🚀 Server ready at http://localhost:${port}/`)
}
startApolloServer().catch((e) => console.log('cannot start server', e))

Another thing that I faced as an issue was with geoip-lite so I just commented the usage.

Ambry answered 26/5, 2023 at 19:8 Comment(0)
B
0

For me, I wasn't sending the response properly.

wrong:

return res.status(200);

correct:

res.status(200).send("");
Basanite answered 3/7, 2023 at 13:1 Comment(0)
S
0

Actually it's async await problem. You also need to await from where you are calling your vercel api endpoint if you don't do this vercel environment skips that api call i think they don't run that in backgroud means you need to await until your api not got executed then do your any other works

My problem solved by this
In your server side program you need to await for axios request to be done

     await axios.post(`${process.env.DOMAIN}/api/sendMail`, {
            email, emailType: "VERIFY", auth: process.env.JWT_TOKEN, otp
        })

if i remove await from it
it will be not send mail and also you need to use promises to make all done before executing other codes in your api

       await new Promise((resolve, reject) => {
        // send mail
        transporter.sendMail(mailOptions, (err, info) => {
            if (err) {
                console.error(err);
                reject(err);
            } else {
                console.log(info);
                resolve(info);
            }
        });
    });
    
    return NextResponse.json({ message: "successfully sent" })
Stanleigh answered 2/2 at 5:13 Comment(0)
G
-1

I had the same issue I did:

 npm run build

in terminal and it is working for me.

Gust answered 25/4, 2023 at 4:32 Comment(1)
Please provide more context to this answer. I believe the question was referring to a NextJS application deployed on vercel and not a local build.Berserker

© 2022 - 2024 — McMap. All rights reserved.