denodrivers / postgres

PostgreSQL driver for Deno

Home Page:https://denodrivers.github.io/postgres

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

The server unexpectedly closing a connection bricks a connection pool

lucacasonato opened this issue · comments

Here is a test case that reproduces the issue:

Deno.test("Attempts reconnection when DB goes away unexpectedly", async function () {
  const cfg = getMainConfiguration();

  const aborter = new AbortController();
  const listener = Deno.listen({ port: 0 });

  const proxy = (async () => {
    for await (const conn of listener) {
      const outbound = await Deno.connect({
        hostname: cfg.hostname,
        port: Number(cfg.port),
      });
      aborter.signal.addEventListener("abort", () => {
        conn.close();
        outbound.close();
      });
      await Promise.all([
        copy(conn, outbound),
        copy(outbound, conn),
      ]).catch(() => {});
    }
  })();

  const pool = new Pool({
    ...cfg,
    port: (listener.addr as Deno.NetAddr).port,
  }, 1);

  const client = await pool.connect();
  await client.queryObject("SELECT 1");
  client.release();

  // This closes ongoing connections. The original connection is now dead, so
  // a new connection should be established.
  aborter.abort();

  const client2 = await pool.connect();
  await client2.queryObject("SELECT 1");
  client2.release();

  listener.close();
  await proxy;
});

While this is an artificial reproduction, I have hit this in the wild for connections to supabase.io servers. They seem to just disconnect after a while, causing the Pool in a state where whatever I do, I get one of these two errors (note the stack traces are not correct, because of a Deno Deploy bug):

ConnectionReset: Connection reset by peer (os error 104)
    at async read (deno:ext/net/01_net.js:21:19)
    at async BufReader.read (https://deno.land/std@0.114.0/io/buffer.ts:314:18)
    at async BufReader.readFull (https://deno.land/std@0.114.0/io/buffer.ts:343:28)
    at async Connection.#readMessage (https://deno.land/x/postgres@v0.14.2/connection/connection.ts:95:9)
    at async Connection.#simpleQuery (https://deno.land/x/postgres@v0.14.2/connection/connection.ts:451:31)
    at async Connection.query (https://deno.land/x/postgres@v0.14.2/connection/connection.ts:650:24)
    at async Server.<anonymous> (file:///src/main.tsx:13:28)
    at async Server.#respond (https://deno.land/std@0.114.0/http/server.ts:246:30)

BrokenPipe: Broken pipe (os error 32)
    at async write (deno:ext/net/01_net.js:26:12)
    at async BufWriter.flush (https://deno.land/std@0.114.0/io/buffer.ts:633:29)
    at async Connection.#simpleQuery (https://deno.land/x/postgres@v0.14.2/connection/connection.ts:443:9)
    at async Connection.query (https://deno.land/x/postgres@v0.14.2/connection/connection.ts:650:24)
    at async Server.<anonymous> (file:///src/main.tsx:13:28)
    at async Server.#respond (https://deno.land/std@0.114.0/http/server.ts:246:30)
commented

@Soremwar same error with postgres@v0.15.0:

ConnectionReset: Connection reset by peer (os error 54)
    at async read (deno:ext/net/01_net.js:21:19)
    at async BufReader.read (https://deno.land/std@0.114.0/io/buffer.ts:383:12)
    at async BufReader.readFull (https://deno.land/std@0.114.0/io/buffer.ts:415:20)
    at async Connection.#readMessage (https://deno.land/x/postgres@v0.15.0/connection/connection.ts:152:5)
    at async Connection.#preparedQuery (https://deno.land/x/postgres@v0.15.0/connection/connection.ts:853:27)
    at async Connection.query (https://deno.land/x/postgres@v0.15.0/connection/connection.ts:930:16)
    at async routerHandler (file:///Users/zheren/git/z1p/src/pages/product/spu-cate-list/get.ts:5:15)
    at async Server.handler (file:///Users/zheren/git/z1p/src/main.ts:14:37)
    at async Server.#respond (https://deno.land/std@0.122.0/http/server.ts:298:18)
BrokenPipe: Broken pipe (os error 32)
    at async write (deno:ext/net/01_net.js:26:12)
    at async BufWriter.flush (https://deno.land/std@0.114.0/io/buffer.ts:745:21)
    at async Connection.#preparedQuery (https://deno.land/x/postgres@v0.15.0/connection/connection.ts:843:5)
    at async Connection.query (https://deno.land/x/postgres@v0.15.0/connection/connection.ts:930:16)

@iugo Are you experiencing this problem with the reproduction that lucacasonato provided?

commented

@iugo Are you experiencing this problem with the reproduction that lucacasonato provided?

I encountered this problem in a new project I was using.

Whenever the backend was idle for a period of time, the backend would get an error when connecting again.

My current solution is, await pool.end() after the error occurs.