情報アイランド

「情報を制する者は世界を制す」をモットーに様々な情報を提供することを目指すブログです。現在はプログラミング関連情報が多めですが、投資関連情報も取り扱っていきたいです。

Heroku+Node.jsの使い方(2)Node.jsアプリケーションの作成

この連載記事ではHerokuの使い方を解説していきます。

なお、この連載記事ではHerokuで利用するプログラミングプラットフォームとしてNode.jsを採用することにします。

今回はHerokuを利用して公開するNode.jsアプリケーション(ウェブサイト)を作成します。

Node.jsアプリケーションの作成

Herokuを利用して公開するNode.jsアプリケーションは基本的には普通のNode.jsアプリケーションと同様に作成します。

Node.jsにはHTTPサーバを作成するためのhttp(s)モジュールが標準で用意されていますので、http(s)モジュールを使用して1からHTTPサーバとしてNode.jsアプリケーションを作成することもできますし、expressモジュールやkoaモジュールなどを利用してNode.jsアプリケーションを作成することもできます。

なお、http(s)モジュールを使用したNode.jsアプリケーションの作成については下の連載記事を参照してください。

また、expressモジュールを利用したNode.jsアプリケーションの作成については下の連載記事を参照してください。

ただし、Herokuを利用して公開するNode.jsアプリケーションを作成する場合には幾つか注意しなければならない点があります。

1つ目はHerokuアプリケーションのHTTPリクエストを処理する仮想マシンに割り当てられたHTTPリクエストを待ち受けるためのポート番号はPORT環境変数の値としてHerokuアプリケーションに与えられるということです。

そのため、Node.jsアプリケーションの場合にはprocess.env.PORTによりPORT環境変数の値として与えられたポート番号を取得し、HTTPサーバの起動の際に待ち受けポート番号として使用しなければなりません

また、HTTPサーバの起動はHerokuアプリケーションの実行が開始してから60秒以内に完了させなければなりませんので注意してください。

2つ目はHerokuアプリケーションが終了される場合にはまずSIGTERMシグナルがHerokuアプリケーションに送信されるということです。

HerokuアプリケーションはSIGTERMシグナルを受信した場合には自身の終了処理を行い、自身を終了しなければなりません。

ただし、この終了処理はSIGTERMシグナルを受信してから30秒以内に完了させなければなりませんので注意してください。

万一30秒以内に終了処理が行われなかった場合にはSIGKILLシグナルがHerokuアプリケーションに送信され、Herokuアプリケーションが強制終了されることになります。

そのため、Node.jsアプリケーションの場合にはprocessオブジェクトのSIGTERMイベントにイベントハンドラを登録し、イベントハンドラではアプリケーションの終了処理を行うようにしなければなりません。

また、HerokuアプリケーションへのSIGTERMシグナルの送信は複数回行われる可能性がありますので注意してください。

そのため、Herokuアプリケーションの終了処理が複数回行われないようにしておかなければなりません。

この2点を踏まえて、HTTPリクエストのリクエストメソッドやURLに応じて様々なテキストデータをHTTPレスポンスとして返す簡単なNode.jsアプリケーションを作成してみると下のようになります。

var express = require('express');
var http = require('http');

var app = express();
app.set('x-powered-by', false);
app.set('case sensitive routing', true);
app.set('strict routing', true);
app.use(function (req, res, next) {
    res.status(200);
    res.type('text/plain; charset=utf-8');
    next();
});
app.get('/', function (req, res, next) {
    res.send('welcome to pizyumi\'s website. this is home page.\r\n');
});
app.get('/author', function (req, res, next) {
    res.send('author is pizyumi.\r\n');
});
app.get('/hello', function (req, res, next) {
    res.send('this is hello page.\r\n');
});
app.get('/hello/*', function (req, res, next) {
    res.send('hello, ' + req.path.split('/')[2] + '.\r\n');
});
app.get('*', function (req, res, next) {
    res.status(404);
    res.send(http.STATUS_CODES[404] + '\r\n');
});
app.all('*', function (req, res, next) {
    res.status(501);
    res.send(http.STATUS_CODES[501] + '\r\n');
});
var server = app.listen(process.env.PORT, function () {
    console.log('http server is running...');

    var f = false;
    process.on('SIGTERM', () => {
        if (f) {
            return;
        }
        f = true;

        console.log('http server is closing...');

        server.close(function () {
            console.log('http server closed.');
            process.exit(0);
        });
    });
});
server.on('error', function (err) {
    console.error(err);
    process.exit(1);
});
pizyumi
プログラミング歴19年のベテランプログラマー。業務システム全般何でも作れます。現在はWeb系の技術を勉強中。
スポンサーリンク

-Heroku, Node.js