做数据迁移工具最怕什么?不是格式转换,是撞上API的隐形天花板。开发Note Bridge——一个把OneNote笔记搬去Notion的工具时,我以为最难的是把OneNote复杂的HTML正确翻译成Notion格式。结果折腾更久的,是微软Graph API的限速机制。
这不是一篇"贴段退避代码就能解决"的文章。OneNote的限速有足够多的边界情况,通用重试循环救不了你——你得建模整个限速系统,而不是只对429错误做反应。
六个独立的限速维度
OneNote的限速不是简单的封顶。它有三个时间维度——每分钟、每小时、并发请求——每个维度又在两个范围执行:单用户和全应用。乘出来就是六个独立限制,漏掉任何一个都会立刻吃到429。
这意味着常见的指数退避策略不够用:你可能没碰每分钟上限,但撞上了每小时天花板。或者单个用户没问题,但全应用总量触顶。每个维度都需要单独记账。
实际体验中,真实限制似乎比文档规定的更宽松。但我们按规范编码——万一微软哪天严格执法,系统不能崩。
缺失的Retry-After头
设计良好的API会在429响应里带上Retry-After头,告诉你什么时候可以安全重试。OneNote Graph API没有。不确定是因为机制太复杂还是别的什么原因。
没有Retry-After,简单退避策略就不够看。你可以每次429后增加等待时间,但没法保证下次请求不被限流。对生产应用来说这是真问题。唯一可靠的方案是实现符合微软规范的限速器——我们用Cloudflare Durable Objects搭了一个,追踪所有维度的用量,自己实现Retry-After供前后端消费。
两个几乎没人用的头
造完限速器后,我们发现Graph其实发了两个有用的响应头——只是容易错过,因为它们不在429路径上。
x-ms-throttle-limit-percentage出现在成功响应里,告诉你离限制多近(0.0到1.0)。超过0.8是黄区,到1.0时下次请求大概率429。x-ms-throttle-scope出现在429响应里,值是User、Application或两者都有,告诉你触发了哪个范围。
这两个头改变了设计。第一个让我们能在吃到429前触发软熔断,不用等系统告诉。第二个让我们把429路由到正确的熔断器——如果是应用范围触发,放慢单个用户没用,得放慢所有用户;如果是用户范围,其他租户可以继续跑。
只对429状态码做反应,就像等火警响了才去看有没有烟。这两个头让你能提前闻到焦味。
热门跟贴