解密MS Graph API Webhook订阅与AWS API Gateway的神秘超时问题

本文详细探讨了在使用MS Graph API Webhook订阅与AWS API Gateway集成时遇到的随机超时问题。作者分享了实现方案、问题排查过程、假设分析以及最终通过切换到公共ALB的解决方案,为开发者提供了宝贵的实践经验。

解密MS Graph API Webhook订阅与AWS API Gateway的神秘超时问题

Microsoft Graph API支持一种订阅资源类型,用于管理其Webhook实现,以便向客户端传递变更通知。订阅功能适用于多种资源,包括Outlook消息——这完美契合了我管理O365共享收件箱中传入消息的需求。

高层次上,实现方案如下:

  • 发起订阅请求,提供自定义的notificationUrl端点
  • 响应通知验证请求
  • 开始在监听器上处理Webhook
  • 定期更新上述订阅——最大过期时间取决于资源类型

实现方案

我的方法相当直接:一个连接到Lambda处理器的API Gateway用于处理Webhook,以及一个CloudWatch规则来触发订阅生命周期管理Lambda。

重要的是,API Gateway背后的Lambda(Webhook请求/响应处理器)除了处理实际的传入订阅通知外,还处理初始订阅验证。以下是验证过程要求的快速总结:

  • 接受传入的HTTP POST请求,查询字符串中包含validationToken值
  • 解码并转义token值
  • 返回HTTP响应,包含:
    • 正文包含解码后的token
    • 状态码为200
    • 内容类型为text/plain
    • 在10秒内交付

Outlook消息的最大过期时间为4230分钟(不到三天),因此我设置了CloudWatch规则每天运行一次以确保安全。这工作得非常完美——每天,订阅扩展Lambda都会被调用,Graph API会成功回复。总往返时间(包括对Webhook监听器的验证请求)通常在一秒内。

神秘超时

上述实现方案按预期工作了数月——直到有一天,在更新/扩展订阅时我开始收到错误:

1
2
3
4
{
	"code": "InvalidRequest",
	"message": "Subscription validation request timed out." 	
}

在我们端没有代码或基础设施变更的情况下,我开始通过手动运行订阅更新请求来调试,例如:

1
2
3
4
5
6
PATCH https://graph.microsoft.com/v1.0/subscriptions/{id}
Content-type: application/json

{
   "expirationDateTime":"2020-09-22T18:23:45.9356913Z"
}

前几次尝试都失败了,出现与上述相同的错误——然而,在第4或第5次尝试时成功了。在几轮测试中,这种情况随机发生,最终以成功响应结束。

正如问题开始前几个月所经历的那样,成功的请求几乎在一秒内返回。值得注意的是,失败的请求确实在某种程度上似乎超时了,因为我直到至少10秒过去后才收到HTTP 400。检查日志后,这些失败的请求似乎从未到达我们的基础设施。

假设

随机成功请求的性质,夹杂在从未到达我们端点的失败中,似乎暗示了某种类型的速率限制——要么在Microsoft端,要么可能在AWS的API Gateway上强制执行。可能是随着时间的推移,使用API Gateway开发的集成数量增加,达到了某个阈值,触发了对从MS Graph API到API Gateway连接的限流。使用公共Webhook监听器测试工具进行的额外故障排除无法重现此问题,似乎进一步指向了API Gateway特有的问题。

Graph API支持拒绝提供帮助,建议我们没有适当的企业支持计划。个人认为,此问题的性质不应需要企业支持计划。如果MS支持的任何人读到本文,我邀请您查看一下,因为这可能影响us-east-1中的其他实现。

解决方案

最终,我通过从API Gateway切换到公共ALB来解决此问题。供参考,这里有一个用于无服务器框架的便捷CloudFormation片段。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计