如何在同时接收具有相同id的多个请求时保持API幂等性?

如何在同时接收具有相同id的多个请求时保持API幂等性?,api,rest,http,idempotent,Api,Rest,Http,Idempotent,从我看到的许多文章和商业API中,大多数人通过要求客户机提供requestId或幂等键(例如)并基本上将requestId响应映射存储在存储器中,从而使他们的API具有幂等性。因此,如果有一个已经在这个映射中的请求进入,应用程序将只返回存储的响应 这对我来说都是好事,但我的问题是如何处理第二个电话打进来而第一个电话仍在进行的情况 这是我的问题 我想理想的行为应该是第二次呼叫一直等到第一次呼叫结束并返回第一次呼叫的响应?人们就是这样做的吗 如果是,第二次呼叫需要等待多长时间才能完成第一次呼叫 如果

从我看到的许多文章和商业API中,大多数人通过要求客户机提供requestId或幂等键(例如)并基本上将requestId响应映射存储在存储器中,从而使他们的API具有幂等性。因此,如果有一个已经在这个映射中的请求进入,应用程序将只返回存储的响应

这对我来说都是好事,但我的问题是如何处理第二个电话打进来而第一个电话仍在进行的情况

这是我的问题

  • 我想理想的行为应该是第二次呼叫一直等到第一次呼叫结束并返回第一次呼叫的响应?人们就是这样做的吗

  • 如果是,第二次呼叫需要等待多长时间才能完成第一次呼叫

  • 如果第二次呼叫有等待时间限制,而第一次呼叫仍然没有结束,它应该告诉客户什么?它是否应该不返回任何响应,以便客户端超时并重试


  • 对于wunderlist,我们使用数据库约束来确保不会重复使用任何请求id(这是我们每个表中的一列)。由于我们的数据库技术(postgres)保证不可能插入违反此约束的两个记录,因此我们只需要对潜在的插入错误做出正确的反应。基本上,我们将这个细节外包给我们的数据存储

    我建议,不管你怎么做,尽量不要在你的应用程序中进行协调。如果您试图知道两件事是否同时发生,那么很可能会出现bug。相反,您可能已经使用了一个系统,可以为您提供所需的保证

    现在,请具体回答您的三个问题:

  • 对我们来说,因为我们使用数据库约束,所以数据库处理让事情排队等待的事情。这就是为什么我个人更喜欢旧的SQL数据库——不是因为SQL或关系,而是因为它们非常擅长锁定和排队。我们使用SQL数据库作为哑的断开连接的表
  • 这在很大程度上取决于您的系统。我们尝试将每个系统和子系统中的所有超时调整到1s左右。我们宁愿快速失败也不愿排队。你可以测量并查看你的第99百分位的计时,如果你事先不知道的话,就把它设置为超时
  • 我们将向客户端返回504HTTP状态(以及相应的响应体)。使用幂等键的原因是,客户端可以重试一个请求,所以我们从不担心超时并让他们这样做。同样,我们宁愿快速超时并解决问题,也不愿让事情排队。如果事情排成一列,那么即使在事情得到解决之后,人们也必须等待一段时间,等待事情变得更好

  • 很难理解第二个调用是来自具有相同请求令牌的同一客户机,还是来自不同的客户机

    通常,对于来自在同一资源上运行的不同客户机的并发请求,您还需要在请求令牌的同时实现版本控制策略,以实现幂等性

    关系数据库中的典型版本策略可能是一个带有触发器的版本列,该触发器可在每次更新记录时自动递增数字

    在此情况下,所有客户机都必须指定其请求令牌以及更新的版本(通常使用IfMatch标头,版本号用作ETag的值)

    在服务器端,当需要更新资源状态时,首先检查数据库中的版本号是否与ETag中提供的版本匹配。如果他们这样做了,您将编写更改并以版本为增量。假设第二个请求与第一个请求在相同的版本号上运行,那么它将以412(或409,取决于您如何解释HTTP规范)失败,并且客户端不应重试

    如果您真的想在第一个请求正在进行时立即停止第二个请求,那么您将采用悲观锁定的方式,这并不适合RESTAPI

    在您实际谈论的客户机由于收到暂时的网络错误而使用相同的请求令牌重试的情况下,情况几乎相同

    两个请求将同时运行,第二个请求将启动,因为第一个请求尚未完成,并且尚未将请求令牌记录到数据库中,但无论哪一个先完成,都将成功并记录请求令牌

    对于另一个请求,它将收到一个版本冲突(因为第一个请求增加了版本),此时它应该重新检查请求令牌数据库表,在其中找到它自己的令牌,并假设它是一个并发请求,在它之前完成并返回200


    这似乎很多,但如果您想在处理REST、幂等性和并发性时涵盖所有奇怪和奇妙的故障模式,这就是处理它的方法。

    >两个请求将同时运行,第二个请求将启动,因为第一个请求仍然没有完成,并且还没有将请求令牌记录到数据库中,但是无论哪一个首先完成,都将成功并记录请求令牌。服务器应该如何处理第二个请求?它应该拒绝吗?我遇到了完全相同的问题,并且对这个(似乎)基本问题在网上没有答案感到愤怒。在我看来,你的问题,尤其是问题1,在这条线索中似乎没有答案。你能解释一下你最终是如何解决这个问题的吗?你使用的方法是什么?