在 nodejs 中设置每次调用超时
Setting a per-call timeout in nodejs
在此先感谢您的帮助。
我正在尝试在 Spanner nodejs 客户端中设置每次调用超时。我已经通读了给定的 Spanner 文档,其中最精彩的部分在此处:https://cloud.google.com/spanner/docs/custom-timeout-and-retry。本文档没有提到您需要提供 gaxOptions
。或者我误会了,鉴于我无法解释我所看到的行为,这不足为奇。
我创建了一个小型存储库来存放此复制品:https://github.com/brg8/spanner-nodejs-timeout-repro。代码也贴在下面。
const PROJECT_ID_HERE = "";
const SPANNER_INSTANCE_ID_HERE = "";
const SPANNER_DATABASE_HERE = "";
const TABLE_NAME_HERE = "";
const { Spanner } = require("@google-cloud/spanner");
let client = null;
client = new Spanner({
projectId: PROJECT_ID_HERE,
});
const instance = client.instance(SPANNER_INSTANCE_ID_HERE);
const database = instance.database(SPANNER_DATABASE_HERE);
async function runQuery(additionalOptions = {}) {
const t1 = new Date();
try {
console.log("Launching query...");
await database.run({
sql: `SELECT * FROM ${TABLE_NAME_HERE} LIMIT 1000;`,
...additionalOptions,
});
console.log("Everything finished.");
} catch (err) {
console.log(err);
console.log("Timed out after", new Date() - t1);
}
};
// Query finishes, no timeout (as expected)
runQuery();
/*
Launching query...
Everything finished.
*/
// Query times out (as expected)
// However, it only times out after 7-8 seconds
runQuery({
gaxOptions: {
timeout: 1,
},
});
/*
Launching query...
Error: 4 DEADLINE_EXCEEDED: Deadline exceeded
at Object.callErrorFromStatus (/Users/benjamingodlove/Developer/spanner-node-repro/node_modules/@grpc/grpc-js/build/src/call.js:31:26)
at Object.onReceiveStatus (/Users/benjamingodlove/Developer/spanner-node-repro/node_modules/@grpc/grpc-js/build/src/client.js:330:49)
at /Users/benjamingodlove/Developer/spanner-node-repro/node_modules/@grpc/grpc-js/build/src/call-stream.js:80:35
at Object.onReceiveStatus (/Users/benjamingodlove/Developer/spanner-node-repro/node_modules/grpc-gcp/build/src/index.js:73:29)
at InterceptingListenerImpl.onReceiveStatus (/Users/benjamingodlove/Developer/spanner-node-repro/node_modules/@grpc/grpc-js/build/src/call-stream.js:75:23)
at Object.onReceiveStatus (/Users/benjamingodlove/Developer/spanner-node-repro/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:299:181)
at /Users/benjamingodlove/Developer/spanner-node-repro/node_modules/@grpc/grpc-js/build/src/call-stream.js:145:78
at processTicksAndRejections (node:internal/process/task_queues:76:11) {
code: 4,
details: 'Deadline exceeded',
metadata: Metadata { internalRepr: Map(0) {}, options: {} }
}
Timed out after 7238
*/
还有我的package.json
{
"name": "spanner-node-repro",
"version": "1.0.0",
"description": "Reproducing timeout wonkiness with Spanner.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@google-cloud/spanner": "^5.15.2"
}
}
如有任何见解,我们将不胜感激!
- 本·戈德洛夫
TLDR
将 retryRequestOptions: {noResponseRetries: 0},
添加到您的 gaxOptions
以便您获得以下选项:
const query = {
sql: 'SELECT ...',
gaxOptions: {
timeout: 1,
retryRequestOptions: {noResponseRetries: 0},
},
};
加长版
幕后发生的事情如下:
- 发送(流式)查询请求,超时发生在服务器returns任何响应之前。
- 默认重试设置包括一个
noResponseRetries: 2
选项,这意味着如果客户端根本没有收到任何响应,请求将重试两次。
- 请求的重试只会在随机重试延迟后开始。每次重试都会增加此延迟。
- 重试两次后(总共发送 3 个请求后),DEADLINE_EXCEEDED 错误将传播到客户端。这些重试大约需要 7 秒,因为第一次重试等待大约 2.5 秒,第二次重试等待 4.5 秒(两个值都包含 1 秒的随机抖动值,因此实际值始终在 6 到 8 秒之间)
设置 noResponseRetries: 0
禁用未收到服务器响应的请求重试。
您还会看到,如果将超时设置为更多 'reasonable' 值,您会看到查询以正常方式超时,因为服务器有机会响应。将它设置为 1500(表示 1500 毫秒,即 1.5 秒)会导致超时按我预期的方式工作,使用您的示例代码。
在此先感谢您的帮助。
我正在尝试在 Spanner nodejs 客户端中设置每次调用超时。我已经通读了给定的 Spanner 文档,其中最精彩的部分在此处:https://cloud.google.com/spanner/docs/custom-timeout-and-retry。本文档没有提到您需要提供 gaxOptions
。或者我误会了,鉴于我无法解释我所看到的行为,这不足为奇。
我创建了一个小型存储库来存放此复制品:https://github.com/brg8/spanner-nodejs-timeout-repro。代码也贴在下面。
const PROJECT_ID_HERE = "";
const SPANNER_INSTANCE_ID_HERE = "";
const SPANNER_DATABASE_HERE = "";
const TABLE_NAME_HERE = "";
const { Spanner } = require("@google-cloud/spanner");
let client = null;
client = new Spanner({
projectId: PROJECT_ID_HERE,
});
const instance = client.instance(SPANNER_INSTANCE_ID_HERE);
const database = instance.database(SPANNER_DATABASE_HERE);
async function runQuery(additionalOptions = {}) {
const t1 = new Date();
try {
console.log("Launching query...");
await database.run({
sql: `SELECT * FROM ${TABLE_NAME_HERE} LIMIT 1000;`,
...additionalOptions,
});
console.log("Everything finished.");
} catch (err) {
console.log(err);
console.log("Timed out after", new Date() - t1);
}
};
// Query finishes, no timeout (as expected)
runQuery();
/*
Launching query...
Everything finished.
*/
// Query times out (as expected)
// However, it only times out after 7-8 seconds
runQuery({
gaxOptions: {
timeout: 1,
},
});
/*
Launching query...
Error: 4 DEADLINE_EXCEEDED: Deadline exceeded
at Object.callErrorFromStatus (/Users/benjamingodlove/Developer/spanner-node-repro/node_modules/@grpc/grpc-js/build/src/call.js:31:26)
at Object.onReceiveStatus (/Users/benjamingodlove/Developer/spanner-node-repro/node_modules/@grpc/grpc-js/build/src/client.js:330:49)
at /Users/benjamingodlove/Developer/spanner-node-repro/node_modules/@grpc/grpc-js/build/src/call-stream.js:80:35
at Object.onReceiveStatus (/Users/benjamingodlove/Developer/spanner-node-repro/node_modules/grpc-gcp/build/src/index.js:73:29)
at InterceptingListenerImpl.onReceiveStatus (/Users/benjamingodlove/Developer/spanner-node-repro/node_modules/@grpc/grpc-js/build/src/call-stream.js:75:23)
at Object.onReceiveStatus (/Users/benjamingodlove/Developer/spanner-node-repro/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:299:181)
at /Users/benjamingodlove/Developer/spanner-node-repro/node_modules/@grpc/grpc-js/build/src/call-stream.js:145:78
at processTicksAndRejections (node:internal/process/task_queues:76:11) {
code: 4,
details: 'Deadline exceeded',
metadata: Metadata { internalRepr: Map(0) {}, options: {} }
}
Timed out after 7238
*/
还有我的package.json
{
"name": "spanner-node-repro",
"version": "1.0.0",
"description": "Reproducing timeout wonkiness with Spanner.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@google-cloud/spanner": "^5.15.2"
}
}
如有任何见解,我们将不胜感激!
- 本·戈德洛夫
TLDR
将 retryRequestOptions: {noResponseRetries: 0},
添加到您的 gaxOptions
以便您获得以下选项:
const query = {
sql: 'SELECT ...',
gaxOptions: {
timeout: 1,
retryRequestOptions: {noResponseRetries: 0},
},
};
加长版
幕后发生的事情如下:
- 发送(流式)查询请求,超时发生在服务器returns任何响应之前。
- 默认重试设置包括一个
noResponseRetries: 2
选项,这意味着如果客户端根本没有收到任何响应,请求将重试两次。 - 请求的重试只会在随机重试延迟后开始。每次重试都会增加此延迟。
- 重试两次后(总共发送 3 个请求后),DEADLINE_EXCEEDED 错误将传播到客户端。这些重试大约需要 7 秒,因为第一次重试等待大约 2.5 秒,第二次重试等待 4.5 秒(两个值都包含 1 秒的随机抖动值,因此实际值始终在 6 到 8 秒之间)
设置 noResponseRetries: 0
禁用未收到服务器响应的请求重试。
您还会看到,如果将超时设置为更多 'reasonable' 值,您会看到查询以正常方式超时,因为服务器有机会响应。将它设置为 1500(表示 1500 毫秒,即 1.5 秒)会导致超时按我预期的方式工作,使用您的示例代码。