运行 while 循环如何或最好的方法来避免 API 限制
How, or best way to run while loop to avoid API limitations
我正在使用 API 请求,这个 API 限制为每秒调用 2 次,每个请求有 250 条记录。这就是要点。
我创建了这个后台作业,它还可以选择第二个后台作业。这可能有点矫枉过正。
流量:
- 从 shopify 创建的订单 webhooks
- 如果 webhooks 失败,那几天的订单每天一次 Cron 作业。
请求目标:
如果在第一个API请求中有>= 250
records/orders,然后在新的worker中创建第二个后台作业,在大约3分钟内获取第2页,如果第 2 页有 >= 250
,然后在同一个工作人员中创建一个新的后台作业有第 2 页(第 2 页完成后)第 2 页作业开始后 3 分钟获取第 3 页,依此类推。我使用 n
对于页面,如果 250 语句为真,则将 1
添加到 n
。
Cron 作业:
shops = Shop.all
shops.map do |shop|
if shop.company.present?
ShopifyOrderUpdatesWorker.perform_later(shop)
end
end
后台作业 1:(第一次 API 调用)
def perform(shop)
n = 1
orders = ShopifyAPI::Order.find(:all, params: {created_at_min: 1.day.ago.beginning_of_day.iso8601}, limit: 250, page: n )
while (orders.count >= 250) || n == 1
unless n =< 1
while n > 1 && orders.count >= 250
orders = ShopifyAPI::Order.find(:all, params: {created_at_min: 1.day.ago.beginning_of_day.iso8601 }, limit: 250, page: n)
#while orders.count >= 250 || n == 2
t = 3
ShopifyOrderUpdatesLimitWorker.delay_for(t.minutes).perform_later(orders)
n += 1 #add page to API call request
t += +3 #add 3 minutes for each loop to buffer the api call queue to avoid api limits to be safe
#end
end
end
if n == 1
orders.map do |order|
#code here
end
end
n += 1
end
end
后台作业 2:(对于第一个之后的任何 API 调用)
def perform(orders)
orders.map do |order|
#code here
end
end
这样,所有商店都可以更新 "quickly",而无需排在其他商店后面。有很多订单的商店将等待相同的时间,无论是在一次操作中还是在 2 次操作中完成所有这些操作。
这是矫枉过正吗?正确完成代码
实际上,webhook 失败的可能性非常小,因此调用第二个后台作业的可能性很小。
对代码有任何可能的改进或建议吗?
这里可能不适合问这个问题,但如果有人有过 shopify 或类似 api 情况的经验,你在做什么?
在规划您的容量和速率限制时 - 首先您应该估计您的数据大小,因为对于每家很少超过几页的几家商店和拥有多页的数千家商店的策略是非常不同的。
由于 Shopify 的速率限制基于 "Leaky bucket" 算法,默认存储桶大小为 40(在撰写本文时,see official docs)- 您最多可以突发 40 api 连续调用,没有任何速率限制,这足以满足一些商店,每个商店有几页。
如果你 have/plan 有更多(或者只是想礼貌) - 最简单的方法是用一个工人为这些任务创建一个单独的队列,这样任务就不会 运行 并行。然后在每个 api 调用之后添加一个 sleep(0.5)
(或更多)——即使您在应用程序的其他地方有其他任意调用,您也不应该达到您的限制。但请准备好接收一个罕见的 429 Too Many Requests
,在这种情况下,请稍等片刻,然后重复该呼叫。
sleep(30) if ShopifyAPI.credit_maxed?
将此添加到您的循环中
我正在使用 API 请求,这个 API 限制为每秒调用 2 次,每个请求有 250 条记录。这就是要点。
我创建了这个后台作业,它还可以选择第二个后台作业。这可能有点矫枉过正。
流量:
- 从 shopify 创建的订单 webhooks
- 如果 webhooks 失败,那几天的订单每天一次 Cron 作业。
请求目标:
如果在第一个API请求中有>= 250
records/orders,然后在新的worker中创建第二个后台作业,在大约3分钟内获取第2页,如果第 2 页有 >= 250
,然后在同一个工作人员中创建一个新的后台作业有第 2 页(第 2 页完成后)第 2 页作业开始后 3 分钟获取第 3 页,依此类推。我使用 n
对于页面,如果 250 语句为真,则将 1
添加到 n
。
Cron 作业:
shops = Shop.all
shops.map do |shop|
if shop.company.present?
ShopifyOrderUpdatesWorker.perform_later(shop)
end
end
后台作业 1:(第一次 API 调用)
def perform(shop)
n = 1
orders = ShopifyAPI::Order.find(:all, params: {created_at_min: 1.day.ago.beginning_of_day.iso8601}, limit: 250, page: n )
while (orders.count >= 250) || n == 1
unless n =< 1
while n > 1 && orders.count >= 250
orders = ShopifyAPI::Order.find(:all, params: {created_at_min: 1.day.ago.beginning_of_day.iso8601 }, limit: 250, page: n)
#while orders.count >= 250 || n == 2
t = 3
ShopifyOrderUpdatesLimitWorker.delay_for(t.minutes).perform_later(orders)
n += 1 #add page to API call request
t += +3 #add 3 minutes for each loop to buffer the api call queue to avoid api limits to be safe
#end
end
end
if n == 1
orders.map do |order|
#code here
end
end
n += 1
end
end
后台作业 2:(对于第一个之后的任何 API 调用)
def perform(orders)
orders.map do |order|
#code here
end
end
这样,所有商店都可以更新 "quickly",而无需排在其他商店后面。有很多订单的商店将等待相同的时间,无论是在一次操作中还是在 2 次操作中完成所有这些操作。
这是矫枉过正吗?正确完成代码
实际上,webhook 失败的可能性非常小,因此调用第二个后台作业的可能性很小。
对代码有任何可能的改进或建议吗?
这里可能不适合问这个问题,但如果有人有过 shopify 或类似 api 情况的经验,你在做什么?
在规划您的容量和速率限制时 - 首先您应该估计您的数据大小,因为对于每家很少超过几页的几家商店和拥有多页的数千家商店的策略是非常不同的。
由于 Shopify 的速率限制基于 "Leaky bucket" 算法,默认存储桶大小为 40(在撰写本文时,see official docs)- 您最多可以突发 40 api 连续调用,没有任何速率限制,这足以满足一些商店,每个商店有几页。
如果你 have/plan 有更多(或者只是想礼貌) - 最简单的方法是用一个工人为这些任务创建一个单独的队列,这样任务就不会 运行 并行。然后在每个 api 调用之后添加一个 sleep(0.5)
(或更多)——即使您在应用程序的其他地方有其他任意调用,您也不应该达到您的限制。但请准备好接收一个罕见的 429 Too Many Requests
,在这种情况下,请稍等片刻,然后重复该呼叫。
sleep(30) if ShopifyAPI.credit_maxed?
将此添加到您的循环中