【问题标题】:Setting a per-call timeout in nodejs在 nodejs 中设置每次调用超时
【发布时间】:2021-12-02 22:58:48
【问题描述】:

在此先感谢您的帮助。

我正在尝试在 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"
  }
}

感谢任何见解!

  • 本·戈德洛夫

【问题讨论】:

    标签: node.js google-cloud-spanner


    【解决方案1】:

    TLDR

    retryRequestOptions: {noResponseRetries: 0}, 添加到您的gaxOptions,以便您获得以下选项:

    const query = {
      sql: 'SELECT ...',
      gaxOptions: {
        timeout: 1,
        retryRequestOptions: {noResponseRetries: 0},
      },
    };
    

    加长版

    幕后发生的事情如下:

    1. (流式)查询请求已发送,并且在服务器返回任何响应之前发生超时。
    2. 默认的重试设置包括noResponseRetries: 2 选项,这意味着如果客户端根本没有收到任何响应,请求将重试两次。
    3. 请求的重试只会在随机重试延迟后开始。每次重试尝试时,此延迟也会增加。
    4. 重试两次后(因此总共发送 3 个请求后)DEADLINE_EXCEEDED 错误将传播到客户端。这些重试大约需要 7 秒,因为第一次重试等待大约 2.5 秒,第二次等待 4.5 秒(这两个值都包含 1 秒的随机抖动值,因此实际值将始终在 6 到 8 秒之间)

    设置noResponseRetries: 0 禁用重试未收到服务器响应的请求。

    您还将看到,如果您将超时设置为更“合理”的值,您将看到查询以正常方式超时,因为服务器有机会响应。将其设置为 1500(意思是 1500 毫秒,即 1.5 秒)会导致超时按照我使用您的示例代码的预期工作。

    【讨论】:

    • 您使用noResponseRetries 的解决方案对我有用!我确实想指出,即使不使用noResponseRetries,即使使用更高的值(如 1.5 秒),我也会得到延长的超时时间。我怀疑是因为查询需要几分钟才能完成。
    猜你喜欢
    • 1970-01-01
    • 2020-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多