9

I am currently building a simple CRUD app using ExpressJS, and host it on Heroku using free account.

The problem I ran into is:

  • GET API for getting all items works on localhost, but show status 503 when hosting on Heroku;
  • POST API for updating one item works on localhost, but same issue as GET API above;
  • All 503 errors are after 30s of loading, this should be a setting from Heroku.

I do have other API end points that work on both local and Heroku server:

  • GET API for getting one item using ID

My guessing:

  • The issue should not be a code issue
  • There is some issue when the code is deployed and Heroku cannot process this request

I tried to find some articles on the web but this seems hard to diagnose, anyone who has experience please let me know how I can solve this issue. Appreciate your comments.

My Mongoose Schema

const mongoose = require("mongoose");

const ThoughtSchema = mongoose.Schema({
  title: {
    type: String,
    required: true
  },
  content: {
    type: String,
    required: true
  },
  date: {
    type: Date,
    default: Date.now
  }
});

module.exports = mongoose.model("Thought", ThoughtSchema);

2 end points that do not work

// Returns all thoughts
router.get("/", async (req, res) => {
  try {
    const thought = await Thought.find();
    res.json(thought);
  } catch (err) {
    res.json({ message: err });
  }
});

// Submit a post
router.post("/", async (req, res) => {
  const thought = new Thought({
    title: req.body.title,
    content: req.body.content
  });

  try {
    const savedThought = await thought.save();
    res.json(savedThought);
  } catch (err) {
    res.json({ message: err });
  }
});

The end point that works

// Specific thought
router.get("/:thoughtId", async (req, res) => {
  try {
    const thought = await Thought.findById(req.params.thoughtId);
    res.json(thought);
  } catch (err) {
    res.json({ message: err });
  }
});

My package.json for this express app

{
  "name": "my-thoughts-app",
  "version": "0.1.0",
  "description": "An app to records user's thoughts",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/PayneTang/my-thoughts-app.git"
  },
  "author": "Payne Tang",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/PayneTang/my-thoughts-app/issues"
  },
  "homepage": "https://github.com/PayneTang/my-thoughts-app#readme",
  "dependencies": {
    "dotenv": "^8.2.0",
    "express": "^4.17.1",
    "mongoose": "^5.8.11"
  },
  "devDependencies": {
    "typescript": "^3.7.5"
  }
}

EDIT: My index.js

const express = require("express");
const path = require("path");
const app = express();
const mongoose = require("mongoose");
const thoughtRoute = require("./routes/thought");
require("dotenv").config();

console.log(process.env);

// Mongoose settings
mongoose.connect(
  process.env.DB_CONNECTION,
  { useNewUrlParser: true, useUnifiedTopology: true },
  () => {
    console.log("Connected to DB!");
  }
);

app.use(express.json());
app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Methods", "*");
  res.header(
    "Access-Control-Allow-Headers",
    "Origin, X-Requested-With, Content-Type, Accept"
  );
  next();
});

app.use("/api/thought", thoughtRoute);
app.get("/api/test", (req, res) => {
  res.send("hi");
});

// Serve client side
app.use(express.static(path.join(__dirname, "client/build")));
app.use(express.static(path.join(__dirname, "client/public")));
// app.get("*", (req, res) => {
//   res.sendFile(path.join(__dirname, "client/build/index.html"));
// });

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
  console.log("Listening on port " + PORT + "...");
});
Payne Tang
  • 151
  • 1
  • 1
  • 6
  • Could we see the `index.js` file? – Zolbayar Feb 11 '20 at 00:11
  • Hi @Zolbayar, I added index.js, thank you. – Payne Tang Feb 11 '20 at 00:14
  • 1
    Can you see the `Listening on port... ` message on Heroku logs after deploying? – Zolbayar Feb 11 '20 at 00:16
  • And have you logged into heroku and checked the logs for your application? (upper right, "More" with double arrow -> "view logs") – Mike 'Pomax' Kamermans Feb 11 '20 at 00:16
  • @zolbayar I can able to see listening to port message. In fact, only two API end points did not work. Others work fine. – Payne Tang Feb 11 '20 at 00:20
  • @mike I use Heroku CLI command: “heroku logs —tail” To check. From what I see, there is no mentioning of the cause, I got an error code and 503 message. I also tried a lot of logging message, seems like the function is not called, it just never begins. – Payne Tang Feb 11 '20 at 00:22
  • What happens if you put a log message above this line? `const thought = await Thought.find();` Can you see the log? – Zolbayar Feb 11 '20 at 00:38
  • What happens if you change the endpoint `"/"` to something like `"/thoughts"`? – Zolbayar Feb 11 '20 at 00:39
  • Have you tried to increase the Heroku timeout limit? – Zolbayar Feb 11 '20 at 00:40
  • There might be an issue with your MongoDB connection too (For example, `Thought.find();` will take much more time than updating a single record) – Zolbayar Feb 11 '20 at 00:41
  • @zolbayar got it. I will check the code based on your suggestions and update. Appreciate your help. – Payne Tang Feb 11 '20 at 00:50
  • Hello @Zolbayar, I tried below 1. changing endpoint does not make any difference because the problem is the Model.find() function. 2. I have waited for 4 mins and no result still. 3. Yes, the console.log before Thought.find() is printed on Heroku. – Payne Tang Feb 11 '20 at 13:05
  • We can say the root cause has been found. But what's next? In other endpoint, findOne function works well. – Payne Tang Feb 11 '20 at 13:07
  • Hi @PayneTang, could you share the endpoint so I could try to fire the API? – Tek Loon Feb 11 '20 at 23:11
  • Hi @TekLoon, currently I deployed to https://my-thoughts-app.herokuapp.com. Single object GET API: /api/thought/:id. All objects GET API: /api/thought. I just found that if i enter an invalid id for the object, the error will be returned. If I enter a valid id, request timeout will happen as well. (e.g. /api/thoughts/5e4176c14e4b550c71de6433) – Payne Tang Feb 15 '20 at 23:47
  • @Zolbayar thanks! i was `.ignoring` my `Context` file. Found out through Heroku logs – Zeeshan Ahmad Khalil May 02 '22 at 12:53

5 Answers5

6

The root cause after checking is due to the access restriction from Heroku to Mongo atlas.

After adding 0.0.0.0/0 for IP whitelist, I am able to get data from MongoDB.

Reference: https://docs.atlas.mongodb.com/security-whitelist/#add-whitelist-entries

Payne Tang
  • 151
  • 1
  • 1
  • 6
  • 2
    after adding 0.0.0.0/0 for IP whitelist, you may need to restart heroku with: `heroku restart -a app_name` – Kevin Apr 26 '21 at 11:58
  • I had the same issue, found out from heroku logs that there was a request timeout - I was sending new requests while old requests have not yet finished. So I refactored my code to send smaller chunks of data with each request and also set up a timeout function. – Marina Kim Oct 18 '21 at 12:42
2

I had the same problem and I was able to fix it by doing these two steps:

  1. Add node version to package.json file:
  "engines": {
    "node": "14.17.3"
  }
}
  1. I changed access settings in MongoDB, allowing access to the database from anywhere (basically, whitelisting 0.0.0.0/0 IP address)
1

In my case, the issue was in package.json I installed two new packages yesterday and in my package.json:

"engines": {
    "node": "12.16.0"
  },

I changed the version to the my current system version:

"engines": {
    "node": "14.5.0"
  },

this is how my 503 service unavailable error gone.

0

This can be caused in several ways to the Node app.

1- Make sure that you specify the right port as what heroku does is it runs our app on a dynamic port.

const PORT = process.env.PORT || 3000;
app.listen(PORT, err => {
  if(err) throw err;
  console.log("%c Server running", "color: green");
});

as described in this comment https://stackoverflow.com/a/52992592/11887902

2- Make sure that you added the Procfile with

npm start

to start the application.

3- If you are using Nodemon and you install it globally, just make sure that you install it locally too.

Finally, just have a look at the logs of the project to figure what heppen to make your project not in the service.

enter image description here

These cases happened to me and caused this error.

Mina
  • 14,386
  • 3
  • 13
  • 26
0

My issue was caused due to case sensitivity that is at times ignored by node, in my controllers I had a file named sessions.js yet when importing in my routes I had mistakenly put ... = require('../controllers/Sessions'), Nodemon was running without issues as I was developing but upon deploying on heroku it crashed so I changed to ... = require('../controllers/sessions') and now it runs ok

m'hd semps
  • 564
  • 4
  • 14