You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

dd-trace埋点导致含for循环的Axios post请求失败时代码运行异常

Express接入dd-trace埋点后请求报错问题修复

问题背景

为了定位ExpressJS应用接入dd-trace埋点后的异常问题,迁移代码后出现两种相似逻辑的代码块表现不一致的情况:
this.client为封装的Axios实例。

正常运行代码

无论POST请求成功或失败均可正常执行:

return (async (fn) => {
  try {
    return Promise.resolve(await fn())
  } catch (e) {
    return Promise.reject(e)
  }

  return Promise.reject(new Error('Unusual Error'))
})(() => this.client.post(`foo/bars`, data, opts))

异常代码

仅请求成功时正常,请求失败时dd埋点抛出异常且程序hang住(单次迭代for循环仅用于复现问题):

return (async (fn) => {
  for (let i = 0; i < 1; i++) {
    try {
      return Promise.resolve(await fn())
    } catch (e) {
      return Promise.reject(e)
    }
  }

  return Promise.reject(new Error('Unusual Error'))
})(() => this.client.post(`foo/bars`, data, opts))

报错栈信息

TypeError: Cannot read property 'push' of undefined
  at DatadogSpan._createContext (/app/node_modules/dd-trace/packages/dd-trace/src/opentracing/span.js:76:32)
  at new DatadogSpan (/app/node_modules/dd-trace/packages/dd-trace/src/opentracing/span.js:30:30)
  at DatadogTracer._startSpanInternal (/app/node_modules/dd-trace/packages/dd-trace/src/opentracing/tracer.js:73:18)
  at DatadogTracer._startSpan (/app/node_modules/dd-trace/packages/dd-trace/src/opentracing/tracer.js:62:17)
  at DatadogTracer.Tracer.startSpan (/app/node_modules/opentracing/lib/tracer.js:61:21)
  at Object.wrapMiddleware (/app/node_modules/dd-trace/packages/dd-trace/src/plugins/util/web.js:104:25)
  at callHandle (/app/node_modules/dd-trace/packages/datadog-plugin-router/src/index.js:111:14)
  at wrapCallHandle (/app/node_modules/dd-trace/packages/datadog-plugin-router/src/index.js:41:14)
  at Layer.handle_error (/app/node_modules/express/lib/router/layer.js:71:5)
  at trim_prefix (/app/node_modules/express/lib/router/index.js:315:13)

根因分析

报错本质是dd-trace的异步执行上下文丢失:

  • dd-trace依赖Node.js的async_hooks能力跟踪请求链路的span上下文,代码中手动给async函数返回值套Promise.resolve/Promise.reject的操作,会打断dd-trace对原始Axios请求Promise的链路埋点逻辑
  • 叠加for循环的块级作用域影响,请求错误触发catch分支返回手动包装的reject Promise时,dd-trace尝试创建新span关联上下文,发现当前执行上下文的span存储对象未初始化,直接触发属性读取报错,未处理的上下文异常进一步阻塞事件循环导致程序hang住。

修复方案

方案1:移除不必要的Promise手动包装(优先推荐)

async函数本身的返回值会自动封装为Promise,直接返回结果/抛出错误即可,不需要手动调用Promise相关方法,修改后代码如下:

return (async (fn) => {
  for (let i = 0; i < 1; i++) {
    try {
      return await fn()
    } catch (e) {
      throw e
    }
  }
  throw new Error('Unusual Error')
})(() => this.client.post(`foo/bars`, data, opts))

修改后dd-trace可以正常跟踪原始Axios请求的Promise链路,上下文不会丢失。

方案2:升级dd-trace版本

该上下文丢失属于dd-trace旧版本的已知问题,在3.0+稳定版已完成修复,直接升级依赖版本即可解决大部分场景的同类报错。

方案3:临时兼容配置

如果暂时无法升级版本或者修改业务代码,可以在dd-trace初始化时添加如下配置开启兼容模式:

const tracer = require('dd-trace').init({
  // 保留原有其他配置
  legacyAsyncHooks: true,
  trackAsyncResources: true
})

该配置会启用旧版异步上下文跟踪逻辑,适配有特殊循环/闭包结构的代码场景。

内容的提问来源于stack exchange,提问作者Dave Newton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 01:27:01