带有 socket.io 和 postgres LISTEN 的 NodeJS

NodeJS with socket.io and postgres LISTEN

我试图让我的前端在我的 postgres 数据库上的某个 table 发生更改时监视事件。

Postgres 事件完美触发,我可以通过 Socker.io 连接将它们中继到,但我遇到了可靠性问题。我在我的服务器上收到 (node:26) UnhandledPromiseRejectionWarning: Error: Client was closed and is not queryable 错误,而且事件通常不会被 Socket 发出和捕获。我假设它与我连接到 Socket / db 客户端的方式有关。

pg 配置:

const {Pool} = require('pg');
const production = process.env.NODE_ENV === 'production';

const connectionString = `postgresql://${process.env.DB_USER}:${process.env.DB_PASSWORD}@${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_DATABASE}`

const pool = new Pool({
    connectionString: process.env.CONNECTION_STRING ? process.env.CONNECTION_STRING : connectionString,
  ssl: production,
  connectionTimeoutMillis : 5000,
  idleTimeoutMillis : 30000
});

index.js

io.of("/marketDetails").on('connect', (socket) => {
  pool.connect((err, client, release) => {
    if (err) { 
      console.log(err);
      return;
    }
    
    client.query('LISTEN update_table');
    
    client.on('notification', async(data) => {
      console.log("notified of table change")
      handleDBEvent(socket, data);
    })

    socket.on("disconnect", () => {
      client.query('UNLISTEN update_table');

    })
    
    release();
  })
});

我收到有关某些 table 更改的通知,但非常不一致。

在任何通知发生之前,您立即 release 访问您获得的数据库客户端,并且每次套接字断开连接时您都会收到错误消息,并且您尝试 运行 UNLISTEN 在 30 秒后连接关闭的已释放客户端上的命令。

改为使用

socket.on("disconnect", async () => {
  try {
    await client.query('UNLISTEN update_table');
  } finally {
    release();
  }
});

顺便说一句,我建议不要为每个 socket.io 客户端获取一个新的数据库连接,数据库对它来说太有价值了。相反,为您的应用程序创建一个客户端(您甚至可能不需要池),让它监听 update_table 事件(可能仅当套接字连接时),然后 broadcast 每个事件都currently-connected 个插座。