18

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.

Usman Abdur Rehman
  • 334
  • 1
  • 3
  • 13
  • 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/contact – leerob May 13 '21 at 03:22
  • @leerob 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 then – Usman Abdur Rehman May 14 '21 at 08:34
  • @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 issue – cymruu May 14 '21 at 08:42
  • 1
    In [this example](https://github.com/vercel/next.js/tree/canary/examples/with-mongodb-mongoose) from Next.js for Mongoose, they've called the db connection function inside the api handler function. See if that works for you. – kausko May 14 '21 at 10:00
  • @cymruu I have deployed my db on atlas. I dont know where else to deploy it lol – Usman Abdur Rehman May 14 '21 at 11:26

9 Answers9

13

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.

Saif Ullah
  • 2,067
  • 1
  • 8
  • 9
8

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.

Yong
  • 584
  • 9
  • 15
  • 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. – Usman Abdur Rehman Jan 13 '22 at 20:55
  • Thanks! It works by allowings access from anywhere on mondoDB – Proustibat Mar 16 '23 at 20:28
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.
yaken
  • 559
  • 4
  • 17
  • I am using mongodb hosted on mongodb atlas. I dont know where else to deploy it for free. – Usman Abdur Rehman May 14 '21 at 11:23
  • 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; – Usman Abdur Rehman May 14 '21 at 11:25
  • 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 db – Usman Abdur Rehman May 14 '21 at 11:25
  • 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. – Viraj Singh May 21 '21 at 05:50
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.

Usman Abdur Rehman
  • 334
  • 1
  • 3
  • 13
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.

Greg
  • 163
  • 1
  • 2
  • 9
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.

Alpha
  • 1,413
  • 3
  • 9
  • 23
0

I had the same issue I did:

 npm run build

in terminal and it is working for me.

ocko
  • 97
  • 6
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.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
0

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

wrong:

return res.status(200);

correct:

res.status(200).send("");
GorvGoyl
  • 42,508
  • 29
  • 229
  • 225