Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions packages/pg-cloudflare/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,22 +87,30 @@ export class CloudflareSocket extends EventEmitter {
write(
data: Uint8Array | string,
encodingOrCallback: BufferEncoding | ((error?: unknown) => void) = 'utf8',
callback: (error?: unknown) => void = () => {}
callback?: (error?: unknown) => void
): true | void {
const encoding = typeof encodingOrCallback === 'function' ? 'utf8' : encodingOrCallback
if (typeof encodingOrCallback === 'function') callback = encodingOrCallback
if (data.length === 0) return callback()
if (data.length === 0) return callback?.()
if (typeof data === 'string') data = Buffer.from(data, encoding)

log('sending data direct:', data)
this._cfWriter!.write(data).then(
() => {
log('data sent')
callback()
callback?.()
},
(err) => {
log('send error', err)
callback(err)
// `Connection._send()` writes without a callback, so a rejected write has
// nowhere to be reported: the query hangs until the socket closes and the
// real reason is lost behind "Connection terminated unexpectedly". Emit
// the failure like a net.Socket would so the connection can report it.
if (callback) {
callback(err)
} else {
this.emit('error', err)
}
}
)
return true
Expand Down
28 changes: 28 additions & 0 deletions packages/pg-esm-test/pg-cloudflare.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,34 @@ describe('pg-cloudflare', () => {
await promise
})

it('should emit error when a write without a callback fails', async () => {
const socket = new CloudflareSocket()
const writeError = new Error('write failed')
socket._cfWriter = { write: () => Promise.reject(writeError) }

const emitted = new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new Error('error event was not emitted')), 100)
socket.once('error', (error) => {
clearTimeout(timer)
resolve(error)
})
socket.write(Buffer.from('x'))
})

assert.equal(await emitted, writeError)
})

it('should report a failed write to the callback rather than emitting error', async () => {
const socket = new CloudflareSocket()
const writeError = new Error('write failed')
socket._cfWriter = { write: () => Promise.reject(writeError) }
socket.once('error', () => assert.fail('error event was emitted despite a callback'))

const reported = await new Promise((resolve) => socket.write(Buffer.from('x'), resolve))

assert.equal(reported, writeError)
})

it('should emit close when ending a socket whose closed promise never settles', async () => {
const socket = new CloudflareSocket()
socket._cfSocket = {
Expand Down
Loading