简体   繁体   中英

Heroku - web.1: crashed in node.js app

So I am trying to deploy my node.js app in heroku for the first time.

After deploying my code and getting to the 6th step in the heroku deployment guide: https://devcenter.heroku.com/articles/getting-started-with-nodejs#scale-the-app

It told me it had deployed fine so I opened up "Application error" - the browser console was 503

Next I added a Procfile to my project, re-deployed and then ran heroku ps top which it returns the following:

=== web (Free): yarn start:production (1)
web.1: crashed 2018/01/30 13:17:05 +0000 (~ 5m ago)

I'm not too sure where to go from here as the heroku guide carries on without explaining what to do if I hit this error.

here are the initial few pages for my node.js app:

package.json

{
  "name": "",
  "version": "2.5.1",
  "description": "",
  "main": "index.js",
  "engines": {
    "node": ">=6.0",
    "npm": ">=3.0"
  },
  "repository": {
    "type": "git",
    "url": ""
  }
  "author": "",
  "license": "",
  "bugs": {
    "url": ""
  },
  "homepage": "",
  "scripts": {
    "start": "better-npm-run start",
    "start:production": "yarn build && yarn start:prod",
    "start:prod": "better-npm-run start:prod",
    "build": "yarn clean:build && better-npm-run build",
    "lint": "yarn lint:js && yarn lint:style",
    "lint:js": "better-npm-run lint:js",
    "lint:style": "better-npm-run lint:style",
    "flow": "better-npm-run flow",
    "test": "better-npm-run test",
    "test:watch": "yarn test --watch",
    "clean:all": "yarn clean:build && yarn clean:test",
    "clean:build": "better-npm-run clean:build",
    "clean:test": "better-npm-run clean:test",
    "coveralls": "better-npm-run coveralls && yarn clean:test"
  },
  "betterScripts": {
    "start": {
      "command": "nodemon ./index.js",
      "env": {
        "NODE_PATH": "./src",
        "NODE_ENV": "development",
        "PORT": 3000
      }
    },
    "start:prod": {
      "command": "node ./index.js",
      "env": {
        "NODE_PATH": "./src",
        "NODE_ENV": "production",
        "PORT": 8080
      }
    },
    "build": {
      "command": "webpack --progress --hide-modules --config ./tools/webpack/config.babel.js",
      "env": {
        "NODE_ENV": "production"
      }
    },
    "lint:js": {
      "command": "eslint ./src ./tools ./index.js"
    },
    "lint:style": {
      "command": "stylelint \"./src/**/*.scss\" --syntax scss"
    },
    "flow": {
      "command": "flow; test $? -eq 0 -o $? -eq 2"
    },
    "test": {
      "command": "jest --coverage",
      "env": {
        "NODE_ENV": "test"
      }
    },
    "clean:build": {
      "command": "rimraf ./public/assets"
    },
    "clean:test": {
      "command": "rimraf ./coverage"
    },
    "coveralls": {
      "command": "cat ./coverage/lcov.info | coveralls"
    }
  },
  "babel": {
    "presets": [
      "env",
      "react",
      "stage-0"
    ],
    "env": {
      "production": {
        "plugins": [
          "transform-remove-console"
        ]
      }
    }
  },
  "eslintConfig": {
    "parser": "babel-eslint",
    "extends": "airbnb",
    "plugins": [
      "react",
      "jsx-a11y",
      "import"
    ],
    "env": {
      "browser": true,
      "node": true,
      "jest": true,
      "es6": true
    },
    "rules": {
      "linebreak-style": 0,
      "global-require": 0,
      "no-underscore-dangle": 0,
      "no-console": 0,
      "react/jsx-filename-extension": [
        1,
        {
          "extensions": [
            ".js",
            ".jsx"
          ]
        }
      ],
      "import/no-extraneous-dependencies": [
        "error",
        {
          "devDependencies": true
        }
      ],
      "function-paren-newline": 0
    },
    "globals": {
      "__CLIENT__": true,
      "__SERVER__": true,
      "__DISABLE_SSR__": true,
      "__DEV__": true,
      "webpackIsomorphicTools": true
    }
  },
  "stylelint": {
    "extends": "stylelint-config-standard",
    "rules": {
      "string-quotes": "single",
      "selector-pseudo-class-no-unknown": [
        true,
        {
          "ignorePseudoClasses": [
            "global",
            "local"
          ]
        }
      ]
    }
  },
  "browserslist": [
    "last 2 versions",
    "not ie <= 8"
  ],
  "jest": {
    "setupFiles": [
      "raf/polyfill",
      "<rootDir>/tools/jest/setup.js"
    ],
    "collectCoverageFrom": [
      "src/containers/**/*.js",
      "src/components/**/*.js",
      "!src/**/__tests__"
    ],
    "moduleNameMapper": {
      ".*\\.(css|scss|sass)$": "<rootDir>/tools/jest/styleMock.js",
      ".*\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/tools/jest/assetMock.js"
    }
  }
}

index.js

/* @flow */

// Use babel-register to precompile ES6 syntax
require('babel-core/register');

const WebpackIsomorphicTools = require('webpack-isomorphic-tools');

// Setup global variables for server
global.__CLIENT__ = false;
global.__SERVER__ = true;
global.__DISABLE_SSR__ = false; // Disable server side render here
global.__DEV__ = process.env.NODE_ENV !== 'production';

// This should be the same with webpack context
const dirRoot = require('path').join(process.cwd());

// Settings of webpack-isomorphic-tools
global.webpackIsomorphicTools =
  new WebpackIsomorphicTools(require('./tools/webpack/WIT.config')).server(dirRoot, () => require('./src/server'));

WIT.config.js

const WebpackIsomorphicToolsPlugin = require('webpack-isomorphic-tools/plugin');

module.exports = {
  // debug: true,
  // webpack_assets_file_path: 'webpack-assets.json',
  // webpack_stats_file_path: 'webpack-stats.json',
  assets: {
    images: {
      extensions: ['png', 'jpg', 'jpeg', 'gif'],
      parser: WebpackIsomorphicToolsPlugin.url_loader_parser,
    },
    fonts: {
      extensions: ['eot', 'ttf', 'woff', 'woff2'],
      parser: WebpackIsomorphicToolsPlugin.url_loader_parser,
    },
    svg: {
      extension: 'svg',
      parser: WebpackIsomorphicToolsPlugin.url_loader_parser,
    },
    style_modules: {
      extensions: ['css', 'scss'],
      filter: (module, regex, options, log) => {
        if (options.development) {
          return WebpackIsomorphicToolsPlugin.style_loader_filter(module, regex, options, log);
        }

        return regex.test(module.name);
      },
      path: (module, options, log) => {
        if (options.development) {
          return WebpackIsomorphicToolsPlugin.style_loader_path_extractor(module, options, log);
        }

        return module.name;
      },
      parser: (module, options, log) => {
        if (options.development) {
          return WebpackIsomorphicToolsPlugin.css_modules_loader_parser(module, options, log);
        }

        return module.source;
      },
    },
  },
};

server.js

   /* @flow */

import path from 'path';
import morgan from 'morgan';
import express from 'express';
import compression from 'compression';
import helmet from 'helmet';
import hpp from 'hpp';
import favicon from 'serve-favicon';
import React from 'react';
import { renderToString, renderToStaticMarkup } from 'react-dom/server';
import { StaticRouter, matchPath } from 'react-router-dom';
import { Provider } from 'react-redux';
import chalk from 'chalk';

import createHistory from 'history/createMemoryHistory';
import configureStore from './redux/store';
import Html from './utils/Html';
import App from './containers/App';
import routes from './routes';
import { port, host } from './config';

const app = express();

app.set('port', process.env.PORT || 3000);

// Using helmet to secure Express with various HTTP headers
app.use(helmet());
// Prevent HTTP parameter pollution.
app.use(hpp());
// Compress all requests
app.use(compression());

// Use morgan for http request debug (only show error)
app.use(morgan('dev', { skip: (req, res) => res.statusCode < 400 }));
app.use(favicon(path.join(process.cwd(), './public/favicon.ico')));
app.use(express.static(path.join(process.cwd(), './public')));

// Run express as webpack dev server
if (__DEV__) {
  const webpack = require('webpack');
  const webpackConfig = require('../tools/webpack/config.babel');

  const compiler = webpack(webpackConfig);

  app.use(require('webpack-dev-middleware')(compiler, {
    publicPath: webpackConfig.output.publicPath,
    hot: true,
    noInfo: true,
    stats: { colors: true },
    serverSideRender: true,
  }));

  app.use(require('webpack-hot-middleware')(compiler));
}

//GET week
app.get('/api/week', (req, res) => {
    console.log('week');

    var articles = [];

    db.collection('articles')
        .find()
        .limit(2)
        .sort("date", -1)
        .toArray()
        .then(result => {
            articles = articles.concat(result);
        }).then(() => {
            // console.log(articles);
            res.send(articles);
        }).catch(e => {
            console.error(e);
        });

});

//GET articles
app.get('/api/articles', (req, res) => {
    console.log('articles');

    var articles = [];

    db.collection('articles')
        .find()
        .limit(12)
        .sort("date", -1)
        .toArray()
        .then(result => {
            articles = articles.concat(result);
        }).then(() => {
            // console.log(articles);
            res.send(articles);
        }).catch(e => {
            console.error(e);
        });

});

//GET authorArticles
app.get('/api/authorArticles', (req, res) => {
    console.log('authorArticles');

    var articles = [];

    var ObjectId = require('mongodb').ObjectID;
    var author = {};
    var param = req.query.authorQuery;
    param = param.replace(/-/g, ' ');

    db.collection('articles')
        // .find()
        .find({"author" : {$regex : ".*" + param + ".*"}})
        .limit(12)
        .sort("date", -1)
        .toArray()
        .then(result => {
            articles = articles.concat(result);
        }).then(() => {
            // console.log(articles);
            res.send(articles);
        }).catch(e => {
            console.error(e);
        });

});

//GET extra
app.get('/api/extra', (req, res) => {
    console.log('extra');

    var articles = [];

    db.collection('articles')
        .aggregate([{ $sample: { size: 4 } }])
        .toArray()
        .then(result => {
            articles = articles.concat(result);
        }).then(() => {
            // console.log(articles);
            res.send(articles);
        }).catch(e => {
            console.error(e);
        });

});

//GET authors
app.get('/api/authors', (req, res) => {
    console.log('authors');

    var authors = [];

    db.collection('authors')
        .find()
        .limit(24)
        .toArray()
        .then(result => {
            // console.log(result);
            authors = authors.concat(result);
        }).then(() => {
            res.send(authors);
        }).catch(e => {
            console.error(e);
        });

});

//GET search
app.get('/api/search', (req, res) => {
    console.log('/api/search');

    var articles = [];

    db.collection('articles')
        .find({$or:[
                {title: {$regex : ".*" + req.query.searchQuery + ".*"}},
                {description: {$regex : ".*" + req.query.searchQuery + ".*"}},
                {author: {$regex : ".*" + req.query.searchQuery + ".*"}},
                {keywords: {$regex : ".*" + req.query.searchQuery + ".*"}}
              ]})
        .limit(24)
        .sort("date", -1)
        .toArray()
        .then(result => {
            articles = articles.concat(result);
        }).then(() => {
            // console.log(articles);
            res.send(articles);
        }).catch(e => {
            console.error(e);
        });

});

//GET category
app.get('/api/category', (req, res) => {
    console.log('category');

    var articles = [];

    db.collection('articles')
        .find({$or:[
                {category: {$regex : ".*" + req.query.categoryQuery + ".*"}}
              ]})
        .limit(12)
        .sort("date", -1)
        .toArray()
        .then(result => {
            articles = articles.concat(result);
        }).then(() => {
            // console.log(articles);
            res.send(articles);
        }).catch(e => {
            console.error(e);
        });

});

//GET article
app.get('/api/article', (req, res) => {
    console.log('article');

    var ObjectId = require('mongodb').ObjectID;
    var article = {};
    var param = req.query.title;
    param = param.replace(/-/g, ' ');

    db.collection('articles')
        .findOne({"title": param})
        .then(result => {
            article = result;
        }).then(() => {
            res.send(article);
        }).catch(e => {
            console.error(e);
        });

});

//GET author
app.get('/api/author', (req, res) => {
    console.log('author');

    var ObjectId = require('mongodb').ObjectID;
    var article = {};
    var param = req.query.title;
    param = param.replace(/-/g, ' ');

    db.collection('authors')
        .findOne({"name": param})
        .then(result => {
            article = result;
        }).then(() => {
            res.send(article);
        }).catch(e => {
            console.error(e);
        });

});

// Register server-side rendering middleware
app.get('*', (req, res) => {
  if (__DEV__) webpackIsomorphicTools.refresh();

  const history = createHistory();
  const store = configureStore(history);
  const renderHtml = (store, htmlContent) => { // eslint-disable-line no-shadow
    const html = renderToStaticMarkup(<Html store={store} htmlContent={htmlContent} />);

    return `<!doctype html>${html}`;
  };

  // If __DISABLE_SSR__ = true, disable server side rendering
  if (__DISABLE_SSR__) {
    res.send(renderHtml(store));
    return;
  }

  // Load data on server-side
  const loadBranchData = () => {
    const promises = [];

    routes.some((route) => {
      const match = matchPath(req.path, route);

      // $FlowFixMe: the params of pre-load actions are dynamic
      if (match && route.loadData) promises.push(route.loadData(store.dispatch, match.params));

      return match;
    });

    return Promise.all(promises);
  };

  // Send response after all the action(s) are dispathed
  loadBranchData()
    .then(() => {
      // Setup React-Router server-side rendering
      const routerContext = {};
      const htmlContent = renderToString(
        <Provider store={store}>
          <StaticRouter location={req.url} context={routerContext}>
            <App />
          </StaticRouter>
        </Provider>,
      );

      // Check if the render result contains a redirect, if so we need to set
      // the specific status and redirect header and end the response
      if (routerContext.url) {
        res.status(301).setHeader('Location', routerContext.url);
        res.end();

        return;
      }

      // Checking is page is 404
      const status = routerContext.status === '404' ? 404 : 200;

      // Pass the route and initial state into html template
      res.status(status).send(renderHtml(store, htmlContent));
    })
    .catch((err) => {
      res.status(404).send('Not Found :(');

      console.error(`==> 😭  Rendering routes error: ${err}`);
    });
});

// connect to mongo db
var db
const MongoClient = require('mongodb').MongoClient
MongoClient.connect('mongodb://dannyjones360:test@ds123930.mlab.com:23930/halftimefront', (err, database) => {
    if (err) return console.log(err);
    db = database
    console.log('db connected');
})

if (port) {
  app.listen(port, host, (err) => {
    const url = `http://${host}:${port}`;

    if (err) console.error(`==> 😭  OMG!!! ${err}`);

    console.info(chalk.green(`==> 🌎  Listening at ${url}`));

    // Open Chrome
    require('../tools/openBrowser')(url);
  });
} else {
  console.error(chalk.red('==> 😭  OMG!!! No PORT environment variable has been specified'));
}

config

module.exports = {
  host: 3000 || 'localhost', // Define your host from 'package.json'
  port: 3000,
  app: {
    htmlAttributes: { lang: 'en' },
    title: 'Rendah',
    titleTemplate: 'Rendah - %s',
    meta: [
      {
        name: 'description',
        content: 'Beats culture magazine',
      },
      {
        name: 'apple-mobile-web-app-title',
        content: 'Vernacare',
      },
      {
        name: 'apple-mobile-web-app-capable',
        content: 'yes',
      },
      {
        name: 'apple-mobile-web-app-status-bar-style',
        content: 'black',
      },
      {
        name: 'theme-color',
        content: '#ffffff',
      },
      {
        name: 'mobile-web-app-capable',
        content: 'yes',
      },
      {
        name: 'theme-color',
        content: '#fff',
      },
    ],
  },
};

Any help or advice would be appreciated - thank you in advance.

After making ammends to Yoni Rabinovitch's answer, I deploy the site and now get:

2018-02-05T11:37:12.562907+00:00 heroku[web.1]: Process exited with status 1
2018-02-05T11:37:12.580445+00:00 heroku[web.1]: State changed from starting to crashed
2018-02-05T11:37:15.775044+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=sleepy-scrubland-78530.herokuapp.com request_id=d7e4d005-d2f9-4c5f-89c8-14f2addc9ebf fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https
2018-02-05T11:37:16.157734+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=sleepy-scrubland-78530.herokuapp.com request_id=0f2a7123-f9bf-4ee0-bbc6-59894e21cc1b fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https
2018-02-05T11:37:19.664289+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=sleepy-scrubland-78530.herokuapp.com request_id=b3748306-5b3a-4dd6-be2c-58a171bafbd1 fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https
2018-02-05T11:37:19.898230+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=sleepy-scrubland-78530.herokuapp.com request_id=99b155b8-17e9-47da-a454-d3d4c6f45ef4 fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https
2018-02-05T11:37:21.262972+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=sleepy-scrubland-78530.herokuapp.com request_id=ca84a061-f834-476f-a269-7a9a8cd4adda fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https
2018-02-05T11:37:21.537896+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=sleepy-scrubland-78530.herokuapp.com request_id=9e6e9096-f6b4-4d73-b0c1-faf921ea8666 fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https

You seem to be setting the PORT env var in your package.json. You should not be doing that for Heroku. Heroku sets if for you automatically. Instead, add something like this in your server.js:

    app.set('port', process.env.PORT || 3000);

The you can subsequently call app.listen(app.get('port'),...)

Try in your Procfile npm run start:production instead of using yarn. One time I got the same App crashed in Heroku because when calling the run scripts with yarn it didn't iniatilize the process global variable.

In the latest deploys I hadn't this problem, but it may be ocurring with you.

I am assuming that you are deploying a fresh/sample app. Can you please try above like for the same process :)

Heroku NodeJs sample app

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM