Cloud Functions中使用全局变量存储mysql连接池是否安全及替代方案
答案
全局pool方案的安全性问题
这种写法完全不安全,你担心的变量覆盖问题确实会发生。
Firebase云函数的同一个运行实例会被复用处理多个请求,同一实例内的全局变量是所有请求共享的。如果func1的两次并发请求落在同一个实例上,第一次请求还未执行完asyncFunc的异步逻辑时,第二次请求就修改了全局pool的值,第一次请求后续操作数据库时就会使用第二次的连接池,访问到错误的数据库。
无需传递pool参数的替代方案
方案1:将pool挂载到请求独有的context对象
每个请求的context对象都是独立的,直接将pool绑定到context上即可,业务函数可以直接从context取值,无需额外传递pool参数:
import * as functions from "firebase-functions"; const mysql = require("mysql"); function cloudFunctionCall(asyncFunc) { return functions .region(region) .https.onCall(async (data: any, context: any) => { try { context.pool = mysql.createPool(getConfig(context)); // 仅传data和context两个原生参数 const result = await asyncFunc(data, context); context.pool.end(); res.send(result); } catch (err) { log("A promise failed to resolve", err); res.status(500).send(err); } }); } // 业务函数示例 async function _func1(data, context) { // 直接从context获取pool,无需单独传参 const pool = context.pool; // 业务逻辑 } export const func1 = cloudFunctionCall(_func1); export const func2 = cloudFunctionCall(_func2);
该方案改造成本极低,完全避免了变量共享问题,适合绝大多数场景。
方案2:使用AsyncLocalStorage实现异步上下文隔离
如果不想让业务函数依赖context参数,可以使用Node.js原生的AsyncLocalStorage实现异步链路内的变量共享,完全不入侵业务函数的参数定义:
import * as functions from "firebase-functions"; import { AsyncLocalStorage } from 'async_hooks'; const mysql = require("mysql"); const poolStorage = new AsyncLocalStorage(); function cloudFunctionCall(asyncFunc) { return functions .region(region) .https.onCall(async (data: any, context: any) => { const pool = mysql.createPool(getConfig(context)); // 将pool存入当前请求的异步上下文 return poolStorage.run(pool, async () => { try { // 仅传data参数,业务函数不需要接收pool或context const result = await asyncFunc(data); pool.end(); res.send(result); } catch (err) { log("A promise failed to resolve", err); res.status(500).send(err); } }) }); } // 业务函数示例 async function _func1(data) { // 从当前异步上下文获取pool const pool = poolStorage.getStore(); // 业务逻辑 } export const func1 = cloudFunctionCall(_func1); export const func2 = cloudFunctionCall(_func2);
该方案可以完全解耦连接池逻辑和业务逻辑,并发请求的异步上下文完全隔离,不会出现变量覆盖问题。
内容的提问来源于stack exchange,提问作者niklash
相关产品推荐
相关产品推荐

