观察到users.messages.list的顺序不是降序



为了同步邮箱,我的应用程序遵循同步建议,尝试查找用户邮箱中最新消息的历史ID。然后我们使用它来进行部分同步。

最近我们注意到这些同步的行为暗示了一个问题。一种解释是,我们收到的是一条更老的消息和历史ID。我已经测试了我们的功能,它似乎工作正常。尽管如此,为了排除潜在的根本原因,我添加了一些检查来检测users.messages.listAPI是否按降序返回结果。这些检查最终被击中,这表明这是一个问题。

这是我的函数,在Go中,用于查找最新的历史ID。这包括我为验证排序而添加的额外检查——本质上,它不是对列表中的第一个条目使用messages.get,而是获取列表中的最后一个条目,然后比较日期/历史ID:列表中的第一个条目应该具有最大的历史ID和日期。

func getLatestHistoryID(ctx context.Context, gmailService *gmail.Service) (uint64, time.Time, error) {
messagesResponse, err := gmailService.Users.Messages.List("me").IncludeSpamTrash(true).Context(ctx).Do()
if err != nil {
return 0, time.Time{}, err
}
messagesList := messagesResponse.Messages
if messagesList == nil || len(messagesList) == 0 {
return 0, time.Time{}, nil
}
latestMessage, err := gmailService.Users.Messages.Get("me", messagesList[0].Id).Context(ctx).Do()
if err != nil {
return 0, time.Time{}, err
} else if latestMessage == nil {
return 0, time.Time{}, nil
}
earliestMessage, err := gmailService.Users.Messages.Get("me", messagesList[len(messagesList)-1].Id).Context(ctx).Do()
if err != nil {
log.Errorf("error doing optional check to validate ordering of message list. %v", err)
} else if earliestMessage == nil {
log.Errorf("unexpected earliest message not retrieved")
} else {
if latestMessage.HistoryId < earliestMessage.HistoryId {
return 0, time.Time{}, fmt.Errorf("message list was not in the expected order by history id! first in list %d (%s), last %d (%s)",
latestMessage.HistoryId, latestMessage.Id,
earliestMessage.HistoryId, earliestMessage.Id)
}
// This could probably fail in rare clock skew cases, but right now we're observing this being a several hour difference between dates.
if latestMessage.InternalDate < earliestMessage.InternalDate {
return 0, time.Time{}, fmt.Errorf("message list was not in the expected order by date! first in list %s (%s), last %s (%s)",
time.UnixMilli(latestMessage.InternalDate).String(), latestMessage.Id,
time.UnixMilli(earliestMessage.InternalDate).String(), earliestMessage.Id)
}
}
return latestMessage.HistoryId, time.UnixMilli(latestMessage.InternalDate), nil
}

我已经找到了几个资源,确认users.messages.list预计将按日期/历史ID下降:

  • Gmail API -使用users.threads.list与users.messages.list获得不同的结果
  • 在调用"Users时,Gmail API返回消息的顺序是什么?消息:list"
  • https://developers.google.com/gmail/api/guides/sync full_synchronization # 3
    • 编辑:最初链接到https://developers.google.com/gmail/api/guides/sync#limitations

当我在本地测试上面的函数时,它按预期工作,并命中最后一行的return语句。然而,我已经观察到数百次的无序检测错误。在失败中,大约9/10次我看到HistoryId检查失败。我相信这在一小部分邮箱中很大程度上是失败的,我目前不确定这种情况发生的比例(正在收集这些)。

是否有任何原因的API可能返回结果无序?我的支票所做的假设有什么问题吗?

API按降序返回结果

如果您检查users.messages.list的文档,您将发现没有按参数排序。这意味着您无法保证数据到达的顺序。

它可能有时按降序到达,有时不按降序到达。没有办法保证,如果有的话,它会在文档中说明顺序。

# restrictions并没有提到任何关于顺序的事情,它只提到它可能可用,也可能不可用。

历史记录通常至少可用一周,甚至更长。

你应该总是在本地排序。

最新更新