代码之家  ›  专栏  ›  技术社区  ›  Prem Anand

在并发请求期间处理相同的外部API调用

  •  0
  • Prem Anand  · 技术社区  · 4 年前

    我有两个控制器

    before_action :get_user
    

    以及这两个控制器中的私有方法

    def get_user
      @user = User.find(params[:id])
      @user.create_profile if @user.profile.nil?
    end
    

    这个 create_profile 方法对第三方服务进行API调用以创建配置文件。当来自同一用户的两个并发请求命中这两个控制器时,当数据库中的概要文件为零时,它会进行重复的API调用(两个)。我如何确保我不会在这里提出两个请求而不是一个请求?

    0 回复  |  直到 4 年前
        1
  •  0
  •   Christian Bruckmayer    4 年前

    理想情况下,API请求应该是等幂的,所以两次这样做不会创建两个概要文件,例如,如果概要文件已经存在,只返回概要文件。

    但是,如果这个API不在您的控制之下,并且您需要确保只完成一次请求,那么有几种方法可以做到这一点。

    一种方法是在执行请求之前通过find_or_create记录来使用数据库锁,锁定它并将其标记为在响应之后外部创建的。

    有点像

    class User
      def create_profile
        profile = profile.first_or_create
        return if profile.external_created_at
    
        profile.lock do
          return if profile.external_created_at
    
          api_response
          profile.update_attributes!(external_created_at: Time.now)
        end
      end
    end
    

    否则,您可以将分布式锁与Redis一起使用。

    https://github.com/leandromoreira/redlock-rb https://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html