Node.jsとPostgreSQLを使った接続管理のベストプラクティス

Node.jsを使ってPostgreSQLのデータベースを操作する際に、接続管理が原因でエラーが発生することがあります。
本記事では、特に接続スロットの枯渇や接続の解放漏れを防ぐためのベストプラクティスを解説します。

よくあるエラーとその原因

PostgreSQLに接続する際、以下のようなエラーが発生することがあります。

エラー例 1:接続の確立失敗

[ERROR] api - "pool" method:"POST" function:"" subfunction:"main" catch: error: could not establish connection
    at /path/to/node_modules/pg-pool/index.js:45:11
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async pool (/path/to/project/src/common/pool.js:14:5)

このエラーは、PostgreSQLに新しい接続を確立できなかったことを示しています。
原因として考えられるのは以下の通りです。

  • データベースサーバが停止している
  • ネットワーク接続の問題
  • 認証エラー(ユーザー名やパスワードの誤り)

エラー例 2:接続スロットの枯渇

[ERROR] api - "test" method:"POST" function:"/nearList" subfunction:"main" catch: error: remaining connection slots are reserved for non-replication superuser and rds_superuser connections
    at /path/to/node_modules/pg-pool/index.js:45:11
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async /path/to/project/src/route/test.js:129:22

このエラーは、PostgreSQLのmax_connections設定を超える接続が発生した場合に表示されます。
特に、接続を適切に解放していない場合や、接続プールの設定が不適切な場合に発生しやすいです。

接続管理のベストプラクティス

Node.jsでは、pgライブラリを使用してPostgreSQLに接続するのが一般的です。
このセクションでは、接続を適切に管理する方法を詳しく説明します。

接続プールの使用

pg.Poolは、デフォルトで接続プールを提供します。
これにより、新しい接続を都度作成するのではなく、既存の接続を再利用することでパフォーマンスを向上させます。
ただし、接続を使用した後は必ずリリースする必要があります。

接続管理の例

以下は、接続を適切に取得し、解放する例です。

const { Pool } = require('pg');

const pool = new Pool({
  user: 'your_username',
  host: 'your_host',
  database: 'your_database',
  password: 'your_password',
  port: 5432,
});

const handleRequest = async (req, res) => {
  const client = await pool.connect(); // 接続を取得
  try {
    const results = await client.query('SELECT * FROM your_table');
    res.status(200).json(results.rows);
  } catch (err) {
    console.error('Error executing query', err.stack);
    res.status(500).json({ error: 'Internal Server Error' });
  } finally {
    client.release(); // 接続を解放
  }
};

module.exports = { handleRequest };

解説

  1. pool.connect(): 接続プールからクライアントを取得します。
  2. client.query(): クエリを実行します。
  3. client.release(): 接続をプールに返します。
    これをfinallyブロックで行うことで、エラー発生時でも接続が解放されます。

finallyを使った安全なリリース

エラー処理を行う際、finallyブロックを使用することで、どのような状況でも接続が解放されることを保証します。
以下は、より複雑なリクエスト処理の例です。

const handleRequest = async (req, res, action) => {
  const client = await pool.connect();
  try {
    const result = await action(client, req);
    res.status(200).json(result);
  } catch (err) {
    console.error('Error:', err);
    res.status(500).json({ error: 'Internal Server Error' });
  } finally {
    client.release(); // 接続を解放
  }
};

module.exports = { handleRequest };

実際のシステムでの例

例えば、ビューテーブルを作成する際、以下のようにdblinkを利用するコードがあります。
この場合も接続管理が重要です。

const createViews = async (client) => {
  await client.query(`SELECT dblink_connect('dblink_name', 'host=host_name dbname=db_name user=db_user password=db_password');`);

  await client.query(`
    CREATE OR REPLACE VIEW your_view AS
    SELECT * FROM DBLINK('dblink_name', 'SELECT * FROM your_table')
    AS your_table (column1 type, column2 type);
  `);
};

上記のコードでは、接続を適切に解放することが特に重要です。

PostgreSQLの設定変更

RDSを使用している場合、max_connectionsの設定を調整することで接続スロットを増やすことができます。
以下はその手順です。

STEP
パラメータグループを確認

RDSコンソールにログインし、該当するデータベースインスタンスのパラメータグループを確認します。

STEP
パラメータの変更

max_connectionsの値を適切に増加させます。

STEP
適用

設定を保存し、インスタンスを再起動します(必要な場合)。

まとめ

Node.jsPostgreSQLを操作する際、接続管理を適切に行うことは非常に重要です。
特に、finallyブロックで接続を確実に解放することで、接続スロットの枯渇やパフォーマンス問題を防ぐことができます。
また、RDSを使用している場合は、必要に応じてmax_connectionsを調整することで、システム全体の安定性を高めることができます。

これらのベストプラクティスを活用し、信頼性の高いアプリケーションを構築してください。


Amazonベストセラー

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA