Skip to content

Client.end never resolves if the socket was already destroyed #2923

Closed
@mastermatt

Description

@mastermatt

I've been debugging this issue kibae/pg-logical-replication#20 and narrowed it down to the Client's end method not resolving (or calling the callback) under certain error conditions.

Minimal reproduction:

const client = new Client(connOpts)
await client.connect()

setImmediate(() => {
  client.connection.stream.resetAndDestroy() // simulate a network outage or the db going offline e.g. ECONNRESET

  setImmediate(async () => {
    await client.end() // <-- never resolves
  })
})

Notably, by the time .end is called, the connection and its stream (a new.Socket instance) have already emitted their close and end events. However, .end relies on an end event from the connection to resolve, unless the connection never connected to begin with.
I believe the check to have .end resolve early should not only look at the _connecting flag, but should also check if the socket has been destroyed.

// if we have never connected, then end is a noop, callback immediately
if (!this.connection._connecting) {

I believe these issues are related:

  1. Connection hang on the server side after ended #2329
  2. Bug in pool.end () never returns when trying to close cleanly #2341
  3. pg version 8.7.1 hangs on await db.end() but before version 8 doesn't #2648

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions