Skip to content

Commit d59cd15

Browse files
phireskycharmander
andauthored
fix stack traces of query() to include the async context (brianc#1762) (brianc#2983)
* fix stack traces of query() to include the async context (brianc#1762) * rename tests so they are actually run * conditionally only run async stack trace tests on node 16+ * add stack trace to pg-native --------- Co-authored-by: Charmander <~@charmander.me>
1 parent 0dfd955 commit d59cd15

File tree

4 files changed

+64
-0
lines changed

4 files changed

+64
-0
lines changed

packages/pg-pool/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ function promisify(Promise, callback) {
3939
const result = new Promise(function (resolve, reject) {
4040
res = resolve
4141
rej = reject
42+
}).catch(err => {
43+
// replace the stack trace that leads to `TCP.onStreamRead` with one that leads back to the
44+
// application that created the query
45+
Error.captureStackTrace(err);
46+
throw err;
4247
})
4348
return { callback: cb, result: result }
4449
}

packages/pg/lib/client.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,11 @@ class Client extends EventEmitter {
520520
if (!query.callback) {
521521
result = new this._Promise((resolve, reject) => {
522522
query.callback = (err, res) => (err ? reject(err) : resolve(res))
523+
}).catch(err => {
524+
// replace the stack trace that leads to `TCP.onStreamRead` with one that leads back to the
525+
// application that created the query
526+
Error.captureStackTrace(err);
527+
throw err;
523528
})
524529
}
525530
}

packages/pg/lib/native/client.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,9 @@ Client.prototype.query = function (config, values, callback) {
174174
result = new this._Promise((resolve, reject) => {
175175
resolveOut = resolve
176176
rejectOut = reject
177+
}).catch(err => {
178+
Error.captureStackTrace(err);
179+
throw err;
177180
})
178181
query.callback = (err, res) => (err ? rejectOut(err) : resolveOut(res))
179182
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict'
2+
var helper = require('../test-helper')
3+
var pg = helper.pg
4+
5+
process.on('unhandledRejection', function (e) {
6+
console.error(e, e.stack)
7+
process.exit(1)
8+
})
9+
10+
const suite = new helper.Suite()
11+
12+
// these tests will only work for if --async-stack-traces is on, which is the default starting in node 16.
13+
const NODE_MAJOR_VERSION = +process.versions.node.split('.')[0];
14+
if (NODE_MAJOR_VERSION >= 16) {
15+
suite.testAsync('promise API async stack trace in pool', async function outerFunction() {
16+
async function innerFunction() {
17+
const pool = new pg.Pool()
18+
await pool.query('SELECT test from nonexistent');
19+
}
20+
try {
21+
await innerFunction();
22+
throw Error("should have errored");
23+
} catch (e) {
24+
const stack = e.stack;
25+
if(!e.stack.includes("innerFunction") || !e.stack.includes("outerFunction")) {
26+
throw Error("async stack trace does not contain wanted values: " + stack);
27+
}
28+
}
29+
})
30+
31+
suite.testAsync('promise API async stack trace in client', async function outerFunction() {
32+
async function innerFunction() {
33+
const client = new pg.Client()
34+
await client.connect();
35+
try {
36+
await client.query('SELECT test from nonexistent');
37+
} finally {
38+
client.end();
39+
}
40+
}
41+
try {
42+
await innerFunction();
43+
throw Error("should have errored");
44+
} catch (e) {
45+
const stack = e.stack;
46+
if(!e.stack.includes("innerFunction") || !e.stack.includes("outerFunction")) {
47+
throw Error("async stack trace does not contain wanted values: " + stack);
48+
}
49+
}
50+
})
51+
}

0 commit comments

Comments
 (0)