我应该使用什么作为文档密钥来保持幂等性?

What should I use as the document key to maintain idempotency?

我应该使用什么作为文档密钥来保持幂等性?

我正在构建一个文本消息应用程序,它使用 CouchDB(在客户端上使用 PouchDB)在本地存储消息。 Twilio(SMS 提供商)为每条消息生成一个 ID,我将其用作 CouchDB 文档 ID。这种从 Twilio 的 API 获取消息的方式是幂等的——如果我两次遇到相同的消息,它只会在我的数据库中存储一个副本。

// twilio API /messages
[
  {smsid: 123, body: 'foo'},
  {smsid: 456, body: 'bar'}
]

// transformed into couchdb docs
[
  {id: 123, doc: {_id: 123, body: 'foo'}},
  {id: 456, doc: {_id: 456, body: 'bar'}}
]

从 twilio 获取消息时很容易做到这一点。但是当用户从客户端应用程序发送出站消息时,还没有twilio ID,因为它还没有发送到twilio。

传统的方法是 POST 将消息发送到我的服务器上的某个端点,然后让服务器将其发送到 twilio,然后在它具有 smsid 后将记录添加到数据库中来自 twilio 的回应。这样做的问题是 (a) 从用户按下 "send" 到消息显示在 UI 之间存在明显的延迟,以及 (b) 我们无法利用 couchdb 的身份验证系统.

相反,我设置它以便客户端生成一个随机 ID,并将其插入数据库(通过 pouchdb w/sync)。然后服务器监视添加的新出站记录并将它们分派给 twilio。

这种方法工作正常,但如果我再次 GET /messages,它不再是幂等的——它会为出站消息创建一个额外的记录,因为我没有包含该消息的 smsid 作为它的键(当它被添加到 couchdb 时它没有 smsid)。

是否有解决此问题的方法或更好的方法?

实现此功能的一个想法是,您必须从每条消息中 rely on other data,并忽略 Twilio 的 smsid

也许将用户 ID、消息正文和时间戳的异常版本散列在一起(例如,int(UNIX-TIMESTAMP-IN-SECONDS/100) 将允许在您的服务器收到消息和 Twilio 确认消息之间有 100 秒的延迟).

感谢您的回复。这是一个艰难的过程。来自 freenode 中#couchdb 的@rnewson 非常友好地花一些时间思考这个问题并提出了一个非常有效的解决方案:

  • couchdb 中的消息文档使用任意_id,可以由服务器或客户端生成
  • 客户端发送消息时,生成一个任意的_id放入数据库。服务器观察到这一点并将其分派给 twilio,然后通过向文档
  • 添加 twilio_id 属性 来更新数据库文档
  • 我创建了一个视图来索引文档 twilio_id
  • 当服务器启动时,它会从 twilio 获取最新消息。为了防止向数据库中添加重复记录,它会为每个 twilio id 查询上述视图。对于每个匹配项,它使用匹配项的 _id_rev 来执行更新。对于没有匹配的记录,它会生成一个新的任意 _id 来执行插入。

任何好奇的人,here's the code

再次感谢您的回复!