-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Implement a PoolError
with dedicated codes
#2498
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,7 +24,7 @@ class PendingItem { | |
} | ||
|
||
function throwOnDoubleRelease() { | ||
throw new Error('Release called on client which has already been released to the pool.') | ||
throw new PoolError('Release called on client which has already been released to the pool.', 'Z0003') | ||
} | ||
|
||
function promisify(Promise, callback) { | ||
|
@@ -58,6 +58,14 @@ function makeIdleListener(pool, client) { | |
} | ||
} | ||
|
||
class PoolError extends Error { | ||
// A PoolError is an error thrown during a Pool operation. Each type of error contains a specific "code", documented in pg-pool’s README. | ||
constructor(message, code) { | ||
super(message) | ||
this.code = code | ||
} | ||
} | ||
|
||
class Pool extends EventEmitter { | ||
constructor(options, Client) { | ||
super() | ||
|
@@ -143,7 +151,7 @@ class Pool extends EventEmitter { | |
if (!this._isFull()) { | ||
return this.newClient(pendingItem) | ||
} | ||
throw new Error('unexpected condition') | ||
throw new PoolError('unexpected condition', 'Z0009') | ||
} | ||
|
||
_remove(client) { | ||
|
@@ -160,7 +168,7 @@ class Pool extends EventEmitter { | |
|
||
connect(cb) { | ||
if (this.ending) { | ||
const err = new Error('Cannot use a pool after calling end on the pool') | ||
const err = new PoolError('Cannot use a pool after calling end on the pool', 'Z0001') | ||
return cb ? cb(err) : this.Promise.reject(err) | ||
} | ||
|
||
|
@@ -192,7 +200,7 @@ class Pool extends EventEmitter { | |
// we're going to call it with a timeout error | ||
removeWhere(this._pendingQueue, (i) => i.callback === queueCallback) | ||
pendingItem.timedOut = true | ||
response.callback(new Error('timeout exceeded when trying to connect')) | ||
response.callback(new PoolError('timeout exceeded when trying to connect', 'Z0005')) | ||
}, this.options.connectionTimeoutMillis) | ||
|
||
this._pendingQueue.push(pendingItem) | ||
|
@@ -334,7 +342,9 @@ class Pool extends EventEmitter { | |
if (typeof text === 'function') { | ||
const response = promisify(this.Promise, text) | ||
setImmediate(function () { | ||
return response.callback(new Error('Passing a function as the first parameter to pool.query is not supported')) | ||
return response.callback( | ||
new PoolError('Passing a function as the first parameter to pool.query is not supported', 'Z0002') | ||
) | ||
}) | ||
return response.result | ||
} | ||
|
@@ -385,7 +395,7 @@ class Pool extends EventEmitter { | |
end(cb) { | ||
this.log('ending') | ||
if (this.ending) { | ||
const err = new Error('Called end on pool more than once') | ||
const err = new PoolError('Called end on pool more than once', 'Z0004') | ||
return cb ? cb(err) : this.Promise.reject(err) | ||
} | ||
this.ending = true | ||
|
@@ -408,3 +418,5 @@ class Pool extends EventEmitter { | |
} | ||
} | ||
module.exports = Pool | ||
module.exports.Pool = Pool | ||
module.exports.PoolError = PoolError | ||
Comment on lines
+421
to
+422
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Putting There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean: replacing My goal was to implement the same kind of structure than There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe what @charmander is trying to say, is that if, instead of error codes like catch (err) {
if (err.code === 'ERR_PG_POOL_UNEXPECTED_STATE') throw err // something's wrong
else if (err.code === 'ERR_PG_POOL_CONNECTION_TIMEOUT') {} // handle overloaded database
else {} // Probably not a pg-pool error
} In this case, you would not even need to export Note that because of the way This also explain his other comment explaining that you don't need to explicit every possible error case. I believe that his first comment is that this feels right in ESM: export default Pool
export { Pool, PoolError } but the following is weird in common-js (pre-ESM) module.exports = Pool
module.exports.Pool = Pool because it is the same as doing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Current implementation mimic the
NoticeOrError
interface frompg-protocol
, cf this messageThat's why it raises
exceptionserrors.That's actually the only one I want to catch for now. For instance in a HTTP API, my goal is to return (a more) meaningful message to the client (in this case a
503
which means that the service is unavailable for now).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t think mimicking the format of PostgreSQL error codes (with values that don’t come from PostgreSQL) is useful. https://nodejs.org/api/errors.html#nodejs-error-codes