diff --git a/cf/src/connection.js b/cf/src/connection.js index 8e79170aeb13efe8c3c77ccede0cd3a115b5e1b5..c17a54b62fefa1f13bc38cd82e25d52ed467c94e 100644 --- a/cf/src/connection.js +++ b/cf/src/connection.js @@ -159,6 +159,14 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose if (terminated) return queryError(q, Errors.connection('CONNECTION_DESTROYED', options)) + // The connection lost its socket (backend death, network close) and has + // not reconnected yet. Reserved connections keep routing queries here, + // and buffering their frames would schedule a flush with nowhere to + // write. Refuse up front the same way `terminated` does, so the query + // settles immediately instead of dangling until pool shutdown. + if (socket === null) + return queryError(q, Errors.connection('CONNECTION_CLOSED', options, socket)) + if (stream) return queryError(q, Errors.generic('COPY_IN_PROGRESS', 'You cannot execute queries during copy')) @@ -254,6 +262,16 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose } function nextWrite(fn) { + if (socket === null) { + // The connection closed between this write being scheduled and the + // immediate firing (or a caller raced the close handler). The close + // path has already settled every in-flight query, so the buffered + // bytes have nowhere to go: drop them instead of crashing the + // process from a timer callback with no try/catch above it. + nextWriteTimer !== null && clearImmediate(nextWriteTimer) + chunk = nextWriteTimer = null + return false + } const x = socket.write(chunk, fn) nextWriteTimer !== null && clearImmediate(nextWriteTimer) chunk = nextWriteTimer = null @@ -427,6 +445,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose error(Errors.connection('CONNECTION_DESTROYED', options)) clearImmediate(nextWriteTimer) + chunk = nextWriteTimer = null if (socket) { socket.removeListener('data', data) socket.removeListener('connect', connected) @@ -440,6 +459,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose remaining = 0 incomings = null clearImmediate(nextWriteTimer) + chunk = nextWriteTimer = null socket.removeListener('data', data) socket.removeListener('connect', connected) idleTimer.cancel() diff --git a/cjs/src/connection.js b/cjs/src/connection.js index 07f6716702ac888215c86ad6e0071aaf55ae519c..949aa427e1afd0f68bc4cdcdf062e571568fd24d 100644 --- a/cjs/src/connection.js +++ b/cjs/src/connection.js @@ -157,6 +157,14 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose if (terminated) return queryError(q, Errors.connection('CONNECTION_DESTROYED', options)) + // The connection lost its socket (backend death, network close) and has + // not reconnected yet. Reserved connections keep routing queries here, + // and buffering their frames would schedule a flush with nowhere to + // write. Refuse up front the same way `terminated` does, so the query + // settles immediately instead of dangling until pool shutdown. + if (socket === null) + return queryError(q, Errors.connection('CONNECTION_CLOSED', options, socket)) + if (stream) return queryError(q, Errors.generic('COPY_IN_PROGRESS', 'You cannot execute queries during copy')) @@ -252,6 +260,16 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose } function nextWrite(fn) { + if (socket === null) { + // The connection closed between this write being scheduled and the + // immediate firing (or a caller raced the close handler). The close + // path has already settled every in-flight query, so the buffered + // bytes have nowhere to go: drop them instead of crashing the + // process from a timer callback with no try/catch above it. + nextWriteTimer !== null && clearImmediate(nextWriteTimer) + chunk = nextWriteTimer = null + return false + } const x = socket.write(chunk, fn) nextWriteTimer !== null && clearImmediate(nextWriteTimer) chunk = nextWriteTimer = null @@ -425,6 +443,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose error(Errors.connection('CONNECTION_DESTROYED', options)) clearImmediate(nextWriteTimer) + chunk = nextWriteTimer = null if (socket) { socket.removeListener('data', data) socket.removeListener('connect', connected) @@ -438,6 +457,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose remaining = 0 incomings = null clearImmediate(nextWriteTimer) + chunk = nextWriteTimer = null socket.removeListener('data', data) socket.removeListener('connect', connected) idleTimer.cancel() diff --git a/src/connection.js b/src/connection.js index 1b1cccde43b4570d5d071d6ffaab2669b3c2065a..8bb205e5b4b92282711ec8d105960508ccfc4252 100644 --- a/src/connection.js +++ b/src/connection.js @@ -157,6 +157,14 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose if (terminated) return queryError(q, Errors.connection('CONNECTION_DESTROYED', options)) + // The connection lost its socket (backend death, network close) and has + // not reconnected yet. Reserved connections keep routing queries here, + // and buffering their frames would schedule a flush with nowhere to + // write. Refuse up front the same way `terminated` does, so the query + // settles immediately instead of dangling until pool shutdown. + if (socket === null) + return queryError(q, Errors.connection('CONNECTION_CLOSED', options, socket)) + if (stream) return queryError(q, Errors.generic('COPY_IN_PROGRESS', 'You cannot execute queries during copy')) @@ -252,6 +260,16 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose } function nextWrite(fn) { + if (socket === null) { + // The connection closed between this write being scheduled and the + // immediate firing (or a caller raced the close handler). The close + // path has already settled every in-flight query, so the buffered + // bytes have nowhere to go: drop them instead of crashing the + // process from a timer callback with no try/catch above it. + nextWriteTimer !== null && clearImmediate(nextWriteTimer) + chunk = nextWriteTimer = null + return false + } const x = socket.write(chunk, fn) nextWriteTimer !== null && clearImmediate(nextWriteTimer) chunk = nextWriteTimer = null @@ -425,6 +443,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose error(Errors.connection('CONNECTION_DESTROYED', options)) clearImmediate(nextWriteTimer) + chunk = nextWriteTimer = null if (socket) { socket.removeListener('data', data) socket.removeListener('connect', connected) @@ -438,6 +457,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose remaining = 0 incomings = null clearImmediate(nextWriteTimer) + chunk = nextWriteTimer = null socket.removeListener('data', data) socket.removeListener('connect', connected) idleTimer.cancel()