概要
のNode.js版です。
環境
- Node.js v18.18.0
- TypeScript v5.2.2
- Express v4.18.2
課題
次のようなアプリケーションコードがあった際に
import type { Express, Request, Response } from "express"; import express from "express"; const app: Express = express(); const port = process.env.port || 8000; app.get("/", (req: Request, res: Response) => { setTimeout(() => { res.end("Hello world"); }, 10000); }); const server = require("http").createServer(app); server.listen(port, () => { console.log("Express server listening on port " + server.address().port); });
サーバ側はデプロイなどで停止することがあります。
Ctrl-C
でSIGINT
を投げると、途中で処理が中断され、
$ curl localhost:8000 curl: (52) Empty reply from server
クライアント側はエラーになります。
対応方法
Graceful Shutdown
次のようなフローでGraceful shutdownを導入します。
1. 終了シグナルを受け取る
まずはSIGINT
シグナルを受け取るように修正します。
process.on('SIGINT')
でできます。
import type { Express, Request, Response } from "express"; import express from "express"; const app: Express = express(); const port = process.env.port || 8000; app.get("/", (req: Request, res: Response) => { setTimeout(() => { res.end("Hello world"); }, 10000); }); const server = require("http").createServer(app); server.listen(port, () => { console.log("Express server listening on port " + server.address().port); }); process.on("SIGINT", () => { console.info("SIGINT signal received."); });
2, 3. 新規リクエストの受付を停め、処理中のリクエストを最後まで実行
終了シグナルを受け取ったら新規リクエストの受付を停め、処理中のリクエストを最後まで実行するようにします。
server.close()
でできます。
process.on("SIGINT", () => { console.info("SIGINT signal received."); server.close((err: any) => { console.log("Http server closed."); if (err) { console.error(err); process.exit(1); } }); });
この時点で先程のcurl: (52) Empty reply from server
も出なくなります。
サーバ
$ npx ts-node src/index.ts
Express server listening on port 8000
^CSIGINT signal received.
Http server closed.
クライアント
$ curl localhost:8000 Hello world
4. その他のリソースを閉じる
必要であればDBなどの接続もきちんと後片付けをして、TCPハーフオープンなコネクションが生まれたりしないようにします。
process.on("SIGINT", () => { console.info("SIGINT signal received."); server.close((err: any) => { console.log("Http server closed."); if (err) { console.error(err); process.exit(1); } mongoose.connection.close(false).then(() => { console.log("MongoDB connection closed."); process.exit(0); }); }); });
その他
今回のサンプルコードはこちら
まとめ
Node.jsでのGraceful Shutdownの導入方法を紹介しました。