Serverless Cron Job重复触发Webhook问题求助
你的定时任务确实按15分钟频率执行,但每次都会触发两次Webhook,甚至在MongoDB状态符合条件的情况下仍重复调用。我帮你梳理几个核心问题点和对应的修复方案:
1. 函数异步操作未正确处理,强制退出导致异常复用
从日志里看到同一个请求ID(10d87735-59e3-11e8-be56-69e06899fa1f)触发了两次Webhook,这大概率是因为你用了process.exit(0)强制终止函数,而Serverless的Lambda执行环境可能被复用,残留的异步操作会在复用环境中再次执行。
同时你调用axios.post时没有用await等待请求完成,函数提前结束后,未完成的异步请求可能在后续复用的实例中继续执行,导致重复触发Webhook。
修复方式:移除所有process.exit调用,改用正常返回确保函数优雅结束,同时等待所有异步操作完成:
// 替换原触发Webhook的代码块 console.log('Trigger WebHook'); // 等待axios请求完成,避免异步操作残留 await axios.post('https://api.netlify.com/build_hooks/*****************'); // 正常返回终止函数 return { statusCode: 200, body: JSON.stringify({ message: 'Webhook triggered successfully' }) };
2. 检查是否存在重复的定时任务规则
虽然你的serverless.yml只配置了一个定时事件,但部署过程中可能残留旧的配置。你可以通过对应的云平台控制台(比如AWS CloudWatch Events)查看是否有重复的规则指向同一个函数,若有多余规则直接删除即可。
3. 给Webhook触发添加幂等性校验
即使函数被意外重复执行,我们也可以通过幂等性保证Webhook只触发一次。比如在MongoDB中记录最后一次触发Webhook的时间,触发前先做校验:
// 在触发Webhook前添加校验逻辑 const lastTriggerRecord = await Sheet.findOne({ type: 'last_webhook_trigger' }); const currentTime = new Date(); // 14分钟的阈值避免时间差导致误判 const isWithinCoolDown = lastTriggerRecord ? currentTime - lastTriggerRecord.createdAt < 14 * 60 * 1000 : false; if (!isWithinCoolDown) { console.log('Trigger WebHook'); await axios.post('https://api.netlify.com/build_hooks/*****************'); // 更新或创建最后触发记录 if (lastTriggerRecord) { await Sheet.findByIdAndUpdate(lastTriggerRecord._id, { createdAt: currentTime }); } else { await Sheet.create({ type: 'last_webhook_trigger', createdAt: currentTime }); } } else { console.log('Webhook already triggered in recent 14 minutes, skip'); }
4. 修正错误处理逻辑
你在创建Sheet失败时用process.exit(1)强制退出,这会导致函数异常终止,Serverless平台可能会自动重试该函数,进而引发重复执行。应该改用抛出错误的方式让middy的httpErrorHandler处理:
// 替换原错误退出代码 console.log(res); throw new Error('Failed to create Salsify export run');
总结修复步骤
- 移除所有
process.exit调用,改用正常return或抛出错误终止函数 - 确保所有异步操作(axios.post、fetch等)都用
await等待完成 - 检查云平台控制台是否存在重复的定时任务规则
- 给Webhook触发逻辑添加幂等性校验
按照这些调整后,应该就能解决重复触发Webhook的问题了。
内容的提问来源于stack exchange,提问作者Taylor Austin

