通过middy包装器访问LaunchDarkly时Lambda函数出现挂起问题
问题根因
- Middy 默认会等待 Node.js 事件循环完全清空后,才会结束本次 Lambda 调用并返回结果
- LaunchDarkly Node 服务端 SDK 初始化完成后,会在后台维持长连接、定时轮询任务用于同步最新的功能标志配置,这些常驻后台任务会导致事件循环一直存在未处理的异步任务,永远无法完全清空
- 两者组合使用时,业务代码逻辑执行完成后,Middy 持续等待事件循环清空,就会进入挂起状态直到 Lambda 超时,本次调用被判定为失败后流事件不会被确认移除,进而触发固定间隔的重复调用
可行解决方案
方案1:关闭事件循环等待(首推,适合绝大多数场景)
在初始化 Middy 时显式配置 callbackWaitsForEmptyEventLoop 为 false,告诉 Lambda 运行时业务代码执行完成后直接结束调用,不需要等待事件循环中的剩余任务,不会影响 LaunchDarkly 后台同步逻辑,实例复用时 SDK 仍可正常工作:
const wrap = f => { return middy(f).use({ before: (request) => { request.context.callbackWaitsForEmptyEventLoop = false } }) };
方案2:显式关闭 LaunchDarkly 客户端(仅适合调用频率极低的场景)
如果 Lambda 函数调用频率非常低,不需要复用实例中的 LaunchDarkly 客户端连接,可以在每次业务逻辑执行完成后显式关闭客户端,清空事件循环中的常驻任务:
const handler = wrap(async (event,context) => { try { logger.info(event); await clientLD.waitForInitialization(); const list = await clientLD.variation( 'tenants-forwarding-to-analytics', { key: 'lambda-function-dynamostreamforwarder' }, [], ); logger.info(list); } catch (e) { logger.error(e.message, e); } finally { await clientLD.close() } return null; });
注意该方案每次调用都会重新初始化 LaunchDarkly 客户端,会额外增加冷启动耗时,不适合调用频率高的场景。
方案3:关闭 LaunchDarkly 后台同步任务(适合不需要实时更新功能标志的场景)
如果你的业务不需要实时同步功能标志配置,可以在初始化 SDK 时关闭后台同步相关的配置,避免生成常驻事件循环的任务:
const clientLD = LaunchDarkly.init(process.env.LaunchDarklySDKKey, { logger, sendEvents: false, stream: false, pollingInterval: 0 });
内容的提问来源于stack exchange,提问作者Vini Bono
相关产品推荐
相关产品推荐

