Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js server not releasing memory

I have a problem running a node/express server. The server runs quite well, but uses a lot of memory with time. It starts at about 70mb memory usage. But then it need about 2mb more for every request. And soon it hits the 1.5GB mark and freezes. It also does not release any memory over time. Do I have any general error in my server.js:

import 'babel/polyfill';
import _ from 'lodash';
import fs from 'fs';
import path from 'path';
import express from 'express';
import ReactDOM from 'react-dom/server';
import router from './router';
import Translator from './core/Translator.js';
import cookieParser from 'cookie-parser';
import StoreContainer from './utils/redux.js';
import { combineReducers } from 'redux';
import reducers from './reducers';
import {setAuthToken, removeAuthToken} from './utils/api';
import i18nLocation from './utils/i18nLocation.js';
import {api, setLangHeader, setProtocol} from './utils/api';
import {clearActiveApartment} from './actions/activeApartment.js';
import {clearCityInfo} from './actions/city.js';
import {setDevice} from './actions/appData.js';
import MobileDetect from 'mobile-detect';
import StaticConfiguration from './constants/StaticConfiguration.js';
import compression from 'compression';

const server = global.server = express();

server.set('port', (process.env.PORT || 5000));
server.use(cookieParser());
server.use(compression());
server.use(express.static(path.join(__dirname, 'public')));

// The top-level React component + HTML template for it
const templateFile = path.join(__dirname, 'templates/index.html');
const template = _.template(fs.readFileSync(templateFile, 'utf8'));

server.get(/^[^.]+$/, async (req, res, next) => {
  setProtocol(req.protocol);

  StoreContainer.emptyStore();
  let store = StoreContainer.store;

  let data = _.pick(req, ['baseUrl', 'ip', 'hostname', 'originalUrl',
    'path', 'protocol', 'headers']);
  api.saveRequest({
    data: data
  }).then(response => {

  }, _.noop);

  try {
    let statusCode = 200;
    let data = { title: '', description: '', css: '', body: '',
      country: '', city: '', lonlat: '', image: '/images/test.jpg', fbId: StaticConfiguration.fbKey,
      analytics: StaticConfiguration.analyticsKey};
    const css = [];
    let lang = Translator.resolveLangForRequest(req);

    lang = 'de';  // TODO: remove this line to allow other langs
    Translator.initialize({descriptor: lang});
    setLangHeader(lang);

    if (req.cookies && req.cookies['wg-token']) {
      setAuthToken(req.cookies['wg-token']);
    }

    const context = {
      onInsertCss: value => css.push(value),
      onSetTitle: value => data.title = value,
      onSetMeta: (key, value) => data[key] = value,
      onPageNotFound: () => statusCode = 404
    };

    await router.dispatch({ path: req.path, context }, (state, component) => {

      // redirect to another page
      if (state.redirect) {
        res.redirect(state.redirect);
      }

      data.body = ReactDOM.renderToString(component);
      data.css = css.join('');
      data.langFile = Translator.resolveLangFile(lang, req);
      data.initialState = JSON.stringify(store.getState());
      data.langCode = lang;
    });

    removeAuthToken();

    let html = template(data);
    res.status(statusCode).send(html);
  } catch (err) {
    next(err);
  }
});

//
// Launch the server
// -----------------------------------------------------------------------------

server.listen(server.get('port'), () => {
  if (process.send) {
    process.send('online');
  } else {
    console.log('The server is running at http://localhost:' + server.get('port'));
  }
});
like image 231
ilse2005 Avatar asked Jan 19 '16 02:01

ilse2005


1 Answers

There may be an issue with the res.direct. It should probably be returned, so that the dispatch function doesn't keep running the data.body =, data.css =, etc. Checking if the request has been redirected might also help, so that the code after the call to await router.dispatch() doesn't get run if you have already redirected.

For example:

let redirected = false
await router.dispatch({ path: req.path, context }, (state, component) => {

  // redirect to another page
  if (state.redirect) {
    redirected = true;
    res.redirect(state.redirect);
    return; // stop data.body, data.css, etc from getting set
  }

  data.body = ReactDOM.renderToString(component);
  data.css = css.join('');
  data.langFile = Translator.resolveLangFile(lang, req);
  data.initialState = JSON.stringify(store.getState());
  data.langCode = lang;
});

if (redirected) return; // already redirected, don't send html
like image 154
David Ulrich Avatar answered Oct 06 '22 00:10

David Ulrich