【发布时间】:2020-08-03 00:48:42
【问题描述】:
我有一个 postgresql 表,每天都有成千上万的时间序列数据。我有一个应用程序允许用户检索这些数据。查询可能会占用 200 毫秒到 30 秒的时间,具体取决于时间范围,因此必须取消这些查询以避免对生产造成无用负载。
由于有数十亿的数据,使用流来检索它们是不可避免的。
所以我设法获得了一个带有数据流的工作端点,就像它在 pg-promise 文档中显示的那样,并通过关闭 pg-query-stream 内的光标使其可以取消。
这是在此端点内完成的示例(在构建查询后调用 dataStream()):
const pgp = require("pg-promise")();
const QueryStream = require("pg-query-stream");
const db = pgp({
host: "1.2.3.4",
port: 5432,
database: "db",
user: "user",
password: "password",
max: 2,
});
// query is an SQL string
dataStream(query, req, res, next) {
const qs = new QueryStream(query);
// "close" event is triggered on client request cancelation
req.on("close", () => {
qs.destroy();
});
return db.stream(qs, s => {
s.pipe(JSONStream.stringify()).pipe(res);
s.on("error", error => handleError(error));
})
.catch(error => handleError(error, query));
}
它适用于几次调用,但在某些时候(快速执行 8 到 10 次调用以检查可取消性),应用程序因此堆栈而崩溃:
\node_modules\pg-promise\node_modules\pg\lib\client.js:346
if (self.activeQuery.name) {
^
TypeError: Cannot read property 'name' of null
at Connection.<anonymous> (\node_modules\pg-promise\node_modules\pg\lib\client.js:346:26)
at Connection.emit (events.js:311:20)
at Socket.<anonymous> (\node_modules\pg-promise\node_modules\pg\lib\connection.js:120:12)
at Socket.emit (events.js:311:20)
at addChunk (_stream_readable.js:294:12)
at readableAddChunk (_stream_readable.js:275:11)
at Socket.Readable.push (_stream_readable.js:209:10)
at TCP.onStreamRead (internal/stream_base_commons.js:186:23)
所以我怀疑调用 qs.destroy() 来关闭流不是正确的方法,即使光标在服务器端被很好地销毁。
感谢 node-postgres 和 pg-promise 开发人员的工作。
【问题讨论】:
-
抱歉编辑量太大,我将 pg-query-stream 更新到 3.0 并且不得不复习一些要点