Buri Memo:

アイデアや気づきとかが雑に書き殴られる

node-postgres の query_timeout でタイムアウトした後、DB のプロセスが残り続ける。

Node.js で PostgreSQL にアクセスするために node-postgres を使っている。設定で query_timeout を設定すると、実行時間が長いクエリをタイムアウトさせることができる。 しかし、タイムアウト後に DB 内のプロセスが残ったままになってリソースを圧迫し続けた。

SELECT * FROM pg_stat_activity;

node-postgres.com

結論

statement_timeout を設定することで、タイムアウト時に DB のプロセスをキャンセルできる。

statement_timeout?: number, // number of milliseconds before a statement in query will time out, default is no timeout
query_timeout?: number, // number of milliseconds before a query call will timeout, default is no timeout

クエリ実行のタイムアウト設定はこの2種類で、説明的にもタイムアウトのタイミングに違いがあるようにしか見えないが、コード見てみると実装が大きく違うっぽい。

DB クライアントのタイムアウト設定はどういう実装かちゃんと確認しておいた方が良さそう。

query_timeout

query_timeout は SQL 実行開始(直前)から一定時間後に例外を出すことで中断している。なので client 側ではタイムアウトになるが DB 上のプロセスは動き続ける。コード上ではこの辺。

readTimeout = config.query_timeout || this.connectionParameters.query_timeout
// ... 中略 ...
readTimeoutTimer = setTimeout(() => {
  var error = new Error('Query read timeout')

  process.nextTick(() => {
    query.handleError(error, this.connection)
  })

  queryCallback(error)

  // we already returned an error,
  // just do nothing if query completes
  query.callback = () => {}

  // Remove from queue
  var index = this.queryQueue.indexOf(query)
  if (index > -1) {
    this.queryQueue.splice(index, 1)
  }

  this._pulseQueryQueue()
}, readTimeout)

https://github.com/brianc/node-postgres/blob/master/packages/pg/lib/client.js#L527-L547

statement_timeout

一方、 statement_timeout は DB との connection 確立時に送信される。コード的にはこの辺り。

    // once connection is established send startup message
    con.on('connect', function () {
      if (self.ssl) {
        con.requestSsl()
      } else {
        con.startup(self.getStartupConf())
      }
    })

    con.on('sslconnect', function () {
      con.startup(self.getStartupConf())
    })

https://github.com/brianc/node-postgres/blob/master/packages/pg/lib/client.js#L115-L126

詳しくコードは読んでいないが、以下と同等にセッションに対して statement_timeout を設定してると思われる。よって、タイムアウトは DB 内で発生するのでプロセスが生き続けることがなくなる。

SET statement_timeout TO 10000;

PostgreSQL ドキュメンテーション: statement_timeout パラメータ