NodeJS 在Fastify中处理MySQL PROTOCOL_CONNECTION_LOST的最佳方法- GCP托管

xxslljrj  于 2023-05-22  发布在  Node.js
关注(0)|答案(1)|浏览(228)

在运行SQL查询时,我的一个项目在生产环境中出现了几个PROTOCOL_CONNECTION_LOST错误代码。在Fastify中处理此问题的最佳方法是什么?
我已经搜索了Stackoverflow,但似乎没有明确的答案。我已经改变了MySQL的配置,允许更高的连接限制,但它没有解决这个问题。
对于这个项目来说,目前的交通量真的不是很高,我担心的是,当交通量增加时,这个问题会变得更加突出。
该项目使用Cloud Run托管在GCP上,并使用GCP Cloud SQL。不确定是否与GCP相关,我可能必须更改,但生产数据库正在高内存机器上运行(4vCPU,26GB内存,100GB SSD,启用高可用性)。
Cloud Run容器有4个CPU,2GB内存,3600个请求超时,1000个并发请求,启动CPU boost启用,最小示例数设置为1,最大设置为100。

MySQL插件:

import fp from 'fastify-plugin'
import mysql from '@fastify/mysql'

const plugin = async (fastify, options, done) => {
    const { config } = fastify;

    fastify.register(mysql, {
        host: config.DB_HOST,
        socketPath: config.DB_SOCKET,
        port: config.DB_PORT,
        user: config.DB_USERNAME,
        password: config.DB_PASSWORD,
        database: config.DB_NAME,
        namedPlaceholders: true,
        promise: true,
        connectionLimit: 100,
        waitForConnections: true
    })

    done()
}

export default fp(plugin)

错误信息:

Error: Connection lost: The server closed the connection.
    at PromisePoolConnection.query (/app/node_modules/mysql2/promise.js:93:22)
    at Object.getErrorSyncedTransactions (file:///app/models/cron.js:33:41)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Object.<anonymous> (file:///app/routes/v1/cron.js:89:39) {
  code: 'PROTOCOL_CONNECTION_LOST',
  errno: undefined,
  sql: undefined,
  sqlState: undefined,
  sqlMessage: undefined
}

查询示例:

import fp from 'fastify-plugin'

const model = (fastify, options, done) => {

    const getPendingPayments = async () => {
        const connection = await fastify.mysql.getConnection()
        const [rows] = await connection.query(
            `SELECT
            t.id,
            t.uuid,
            t.status_code,
            y.consent_token AS consent_token,
            y.payment_payload->>'$.data.id' AS payment_id,
            m.id AS merchant_id,
            m.uuid AS merchant_uuid,
            m.webhook_url,
            m.webhook_status
            FROM transactions t 
            JOIN transactions_yapily y 
            ON t.id = y.transaction_id
            JOIN merchants m
            ON m.id = t.merchant_id
            WHERE y.payment_payload IS NOT NULL
            AND t.status_code IN ('ACCP', 'ACSP', 'ACTC', 'ACWC', 'ACWP', 'ACFC', 'RCVD', 'PDNG')
            AND t.created_at >= DATE_SUB(NOW(), INTERVAL 3 HOUR)`
        )
        connection.release()
        return rows
    }

    fastify.decorate('cron', {
        getPendingPayments,
    })

    done()
}

export default fp(model)
du7egjpx

du7egjpx1#

代码显示了异步和同步代码风格的混合。
在异步插件函数中,不要使用done回调。这会导致意想不到的行为。
否则,可以通过删除async关键字来使用done回调。

import fp from 'fastify-plugin'
import mysql from '@fastify/mysql'

const plugin = async (fastify, options) => {
    const { config } = fastify;

    fastify.register(mysql, {
        host: config.DB_HOST,
        socketPath: config.DB_SOCKET,
        port: config.DB_PORT,
        user: config.DB_USERNAME,
        password: config.DB_PASSWORD,
        database: config.DB_NAME,
        namedPlaceholders: true,
        promise: true,
        connectionLimit: 100,
        waitForConnections: true
    })

    // done() in an async function do not use the `done` callback
}

export default fp(plugin)

另一件重要的事情是,由于您正在使用promise: true参数,因此始终释放处理程序中的连接:connection.release()

相关问题