Search code examples
node.jsexpressamazon-ec2google-api

GoogleApis - JavaScript heap out of memory


I am building a service that integrates Google Apis using NodeJs with Express. Everything works fine on my local environment, but when I try to deploy it to my EC2 instance, I get a JavaScript heap out of memory error and then the application crashes.

When I remove the code that instantiates the OAuth2Client, the app works fine.

Here are more information on the problem.

index.ts

import express from 'express';
import dotenv from 'dotenv';
import { google } from 'googleapis';

// ... some more boilerplate code

const googleApiRoutes = require('./routes/googleApiRoutes');

app.use('/api/google-api', googleApiRoutes);

// the instantiation that makes the app crash
export const OAuth2Client = new google.auth.OAuth2(
    process.env.GOOGLE_APIS_CLIENT_ID,
    process.env.GOOGLE_APIS_CLIENT_SECRET,
    process.env.GOOGLE_API_REDIRECT_URL
);

app.listen(process.env.PORT || 5007, () => {
    console.log(`[server]: Server is running at http://localhost:5007`);
});

package.json

{
  "name": "loopfive-services",
  "version": "1.0.0",
  "description": "A general service api useful for various projects",
  "main": "index.ts",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "prettier": "prettier --write .",
    "start": "nodemon index.ts"
  },
  "author": "Ilyes Hadji",
  "license": "ISC",
  "dependencies": {
    "@types/express": "^4.17.21",
    "@types/node": "^22.0.0",
    "body-parser": "^1.20.2",
    "config": "^3.3.6",
    "cookie-parser": "^1.4.6",
    "cors": "^2.8.5",
    "dotenv": "^16.4.5",
    "express": "^4.18.3",
    "express-formidable": "^1.2.0",
    "express-session": "^1.17.2",
    "express-validator": "^7.0.1",
    "form-data": "^4.0.0",
    "formidable-serverless": "^1.1.1",
    "google-auth-library": "^9.14.0",
    "googleapis": "^142.0.0",
    "helmet": "^4.4.1",
    "mailgun.js": "^10.2.3",
    "method-override": "^3.0.0",
    "node-fetch": "^3.3.2",
    "nodemailer-mailgun-transport": "^2.1.5",
    "nodemon": "^3.1.4",
    "ts-node": "^10.9.2"
  },
  "devDependencies": {
    "typescript": "^5.5.4",
    "prettier": "^3.3.3"
  },
  "engines": {
    "node": ">=20.11.1"
  }
}

Error

<--- Last few GCs --->
Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: [51750:0x5b6f280]    13591 ms: Scavenge (reduce) 477.6 (486.1) -> 477.2 (486.4) MB, 5.85 / 0.00 ms  (average m>
Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: [51750:0x5b6f280]    13769 ms: Mark-Compact (reduce) 477.9 (486.4) -> 477.7 (487.4) MB, 95.09 / 0.01 ms  (+ 30>
Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: <--- JS stacktrace --->
Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: ----- Native stack trace -----
Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]:  1: 0xb86ecf node::OOMErrorHandler(char const*, v8::OOMDetails const&) [node]
Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]:  2: 0xef74d0 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node]
Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]:  3: 0xef77b7 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, v8::OOMDetails con>
Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]:  4: 0x1109355  [node]
Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]:  5: 0x11211d8 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectio>
Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]:  6: 0x10f72f1 v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType>
Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]:  7: 0x10f8485 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationTyp>
Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]:  8: 0x10d5ad6 v8::internal::Factory::NewFillerObject(int, v8::internal::AllocationAlignment, v8::internal::All>
Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]:  9: 0x1531906 v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [no>
Aug 27 04:11:56 ip-172-31-39-135 loopfive_services[51750]: 10: 0x196aef6  [node]
Aug 27 04:11:57 ip-172-31-39-135 loopfive_services[51749]: Aborted (core dumped)

Solution

  • With more investigation, I was able to see that solely importing google from googleapis was making my app crash.

    // Problematic code
    import {google} from 'googleapis'
    

    I was able to resolve the issue, as per the comments on the question, by simply scaling my instance type.

    I was using t2.micro, but nothing under t2.medium was doing the trick. I did try t2.small, but it was failing due to the same reasons.