【问题标题】:How to split a long-lived Sidekiq job into many short-lived jobs in a Ruby on Rails app如何在 Ruby on Rails 应用程序中将长期存在的 Sidekiq 作业拆分为多个短期作业
【发布时间】:2019-11-11 21:34:12
【问题描述】:

因此,我正在构建一个调用第三方 API 的网站,该 API 可能需要 20 秒到 30 分钟才能返回结果。但是我不能提前知道这个持续时间,所以需要经常轮询它以检查工作是否完成(返回“COMPLETE”和结果)或没有(返回“IN_PROGRESS”)。此外,该 API 可能会同时被多个用户多次调用。

所以我创建了一个 Sidekiq 工作程序,它每 5 秒检查一次 API,直到它收到“COMPLETE”,然后才结束。但我读到 Sidekiq 应该只做短暂的工作,我正在努力弄清楚我应该如何去做。此外,我一直在尝试寻找答案,但我怀疑我不知道要查找的内容。

我确信有一种方法可以告诉我的工作人员调用 API 一次,如果结果是“IN_PROGRESS”结束,但确保另一个工作人员将执行另一个 API 调用来检查,依此类推直到结果为“COMPLETE”。

另外,我想这对于更好地分配负载也很方便,以防许多用户要求使用所述 API,因为更少的工人可以做更多的这种短期工作。

这是我的工人,我希望能澄清我现在在做什么:

class ThingProgressWorker
  include Sidekiq::Worker

  def perform(id)
    @thing = Thing.find(id)
    @thing_api_call = ThingAPICall.new // This uses the ruby library of the API
    completed = false
    while completed == false
      result = @thing_api_call.get_result( { thing_job_name: @thing.job_name })
      if !result.include? "COMPLETED"
        completed = false
        sleep 5
      else
        completed = true
        @thing.status = "completed"
        @thing.save
        break
      end
    end
  end
end

因此,如果 API 从“IN_PROGRESS”到“COMPLETED”需要 10 分钟,则该工作人员将忙那么长时间,我认为根本不建议这样做。

我已经考虑了几个小时了,我想不出我应该如何让每个 API 调用它自己的工作,而不让工作人员忙于 API 完成。

到目前为止,我想到的唯一解决方案是让一个主工作器为每个 API 调用调用另一个工作器,但是只要 API 需要发送结果,我仍然会有一个工作器忙碌。

如果有任何帮助或指示,我将不胜感激!

提前致谢

【问题讨论】:

    标签: ruby-on-rails sidekiq


    【解决方案1】:

    尝试延迟呼叫工人。例如:

    class ThingProgressWorker
      include Sidekiq::Worker
    
      def perform(id)
        @thing = Thing.find(id)
        @thing_api_call = ThingAPICall.new // This uses the ruby library of the API
          result = @thing_api_call.get_result( { thing_job_name: @thing.job_name })
          if !result.include? "COMPLETED"
            ThingProgressWorker.perform_in(1.minute, id)
          else
            completed = true
            @thing.status = "completed”
            @thing.save
          end
      end
    end
    
    

    这会将工作人员添加到队列中,但不会立即运行,而是在您指定的时间运行。

    【讨论】:

    • 对不起,我想我没有正确解释。并不是我想延迟作业的执行,而是我希望将 loooooooooooong 的作业拆分成更短的作业。还是谢谢!
    • 我的意思是,如果进程未在 api 中完成,您将再次从内部调用 worker,而不是 while 循环。因此,您将有一个短暂的工作人员调用自己在 x 秒或几分钟内再次执行。如果你说延迟 1 分钟,它将在 20 分钟内运行 20 次(每次几秒)
    • 我工作了一半,但不能完全工作。它确实会延迟调用自己(这是我想要的),但它会无限期地调用 ThingProgressWorker(本身),即使在工作完成并且 if 循环应该执行 else 语句中的部分之后也是如此。即使结果.include? “COMPLETED”应该是真的,它从来没有真正进入else下的语句
    • 那么现在的问题是关于 if 条件。任务完成后能否显示 API 响应?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-07
    • 2014-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-06
    相关资源
    最近更新 更多