Azure Function中Node.js定时函数间歇性DNS解析失败求助
Azure消费计划Node.js定时函数间歇性DNS解析失败(EAI_AGAIN)问题排查与解决建议
问题背景
运行在Azure Linux环境、消费计划下的Node.js v18定时函数,每30分钟执行一次,出现间歇性DNS解析异常:正常运行数天后,会持续12-24小时无法解析api.hubapi.com,之后自动恢复。报错发生在@hubspot/api-client调用HubSpot API时,具体错误日志:
Exception: request to https://api.hubapi.com/crm/v3/objects/products?limit=100&after=2663219990&properties=hs_lastmodifieddate%2Chs_sku%2Chs_images&archived=false failed, reason: getaddrinfo EAI_AGAIN api.hubapi.com
已尝试的排查措施:
- 更新
@hubspot/api-client至最新版本,排除库本身问题 - 将Function App出站DNS改为Cloudflare(1.1.1.1)和Quad9(9.9.9.9),替换默认Azure DNS
该函数在本地及GCP环境运行正常。
针对性解决建议
1. 针对消费计划实例特性添加DNS解析重试逻辑
Azure消费计划的实例会频繁启停、回收,可能导致DNS缓存异常或解析请求临时被限流。建议在代码中针对EAI_AGAIN错误添加重试机制:
- 使用
p-retry等重试库,配置针对DNS解析错误的重试策略,比如间隔10秒、最多重试5次 - 或者在
@hubspot/api-client的配置中开启内置重试(如果支持),明确指定包含EAI_AGAIN的错误码
示例代码片段:
const pRetry = require('p-retry'); const { Client } = require('@hubspot/api-client'); const hubspotClient = new Client({ accessToken: 'YOUR_TOKEN' }); async function fetchProducts() { return pRetry(async () => { const response = await hubspotClient.crm.products.getPage(100, '2663219990', ['hs_lastmodifieddate', 'hs_sku', 'hs_images'], false); return response; }, { retries: 5, factor: 2, minTimeout: 10000, onFailedAttempt: (error) => { console.log(`重试第 ${error.attemptNumber} 次,原因: ${error.message}`); }, shouldRetry: (error) => { // 仅针对DNS解析失败的EAI_AGAIN错误重试 return error.message.includes('EAI_AGAIN'); } }); }
2. 手动解析域名绕过系统DNS缓存
在调用API前,手动用Node.js dns模块解析api.hubapi.com的IP,直接使用IP发起请求(需处理SNI,指定主机头):
const dns = require('dns').promises; const https = require('https'); async function fetchWithManualDns() { const ips = await dns.resolve4('api.hubapi.com'); const ip = ips[0]; // 取第一个解析到的IP const options = { hostname: ip, port: 443, path: '/crm/v3/objects/products?limit=100&after=2663219990&properties=hs_lastmodifieddate%2Chs_sku%2Chs_images&archived=false', method: 'GET', headers: { 'Host': 'api.hubapi.com', // 必须指定主机头以支持SNI 'Authorization': 'Bearer YOUR_TOKEN' } }; return new Promise((resolve, reject) => { const req = https.request(options, (res) => { let data = ''; res.on('data', (chunk) => data += chunk); res.on('end', () => resolve(JSON.parse(data))); }); req.on('error', reject); req.end(); }); }
3. 检查Azure消费计划的网络限制
- 确认Function App所在区域的Azure服务健康状态,排查是否存在区域性DNS服务波动
- 配置
WEBSITE_DNS_REFRESH_INTERVAL环境变量(单位秒),强制缩短DNS缓存刷新周期,比如设置为300(5分钟) - 考虑临时切换到弹性计划测试,排除消费计划特有的网络隔离或资源限制问题
4. 验证自定义DNS配置有效性
虽然已配置自定义DNS,但需确认配置是否生效:
- 在函数代码中添加DNS解析测试,调用
dns.resolve('api.hubapi.com')并打印解析结果 - 检查Function App的网络配置,确保自定义DNS服务器地址未被防火墙或网络规则拦截
内容的提问来源于stack exchange,提问作者wooters
相关产品推荐
相关产品推荐

