处理批量 api 长调用的最佳实践
Best practice to handle batch of long api calls
我正在设计一个用户界面来上传用户列表(电子邮件、姓名等...),在该过程结束时,每个用户都会插入我的数据库并收到一封电子邮件.
处理此任务的后端 api 内置于 rails 上的 ruby。
目前对输入的大小没有限制,因此我想为 UI 用户提供一种在整个上传过程中取消剩余作业而不取消已发送作业的方法。
我还想在 GUI 上提供正在处理、已经完成的作业的实时状态。
此外,我想确保同时处理这些作业的作业数量是有限的,这样服务器上的其他用户就不会受到影响。
话虽如此...并且凭借我有限的后端/java脚本知识,我想我会做的是为每个用户(或者可能是一个分组)产生单独的 ajax 调用多个用户),使用 java 限制任何时候只有 X ajax 次调用可以同时进行 运行 (我希望这是可能的)并且每次调用时 returns我将更新 UI 以反映作业的状态,然后为下一组作业生成另一个,直到整个事情完成。如果 UI 用户希望取消,他们可以在已完成的作业保持完成。
这是明智的还是有更好的方法。
提前致谢
我使用 sidekiq 来完成这样的任务。它完全符合您的要求。
你设置了一些worker,它们是你服务器上的线程。然后,当 POST 或其他请求从 UI 传入时,您将每个请求作为 sidekiq 中的一项工作排队,并立即将 return 状态返回给浏览器,因此他们不必等待想知道是否会成功、永远挂起或被 Web 服务器超时。
稍后,作业将被异步处理。它可以更新数据库中的状态以进行报告。
这是在 sidekiq 下运行的 worker 示例:
class PageFetcher
include Sidekiq::Worker
def perform page_id
page = Page.find(page_id)
path = Page.absolute_path
# Do some big, long, error-prone thing with external depencies:
File.binwrite(path, open(page.source_url).read)
saved_size = File.size(path)
if page.expected_file_size != saved_size.to_s
bad_path = path + '.bad'
File.rename(path, bad_path)
# Raise an error, and sidekiq will automatically wait a while and try again later:
raise IOError, "Could not cache #{page.source_url} to #{path}. " +
"File size is #{saved_size}, expected #{page.file_size}. "
end
# update some status field, so this success can be reported:
page.make_status_cached!
# do something else that depends on this success:
page.notify_page_indexer
end
end
当您收到新请求时,创建一个新页面,然后按如下方式排队处理:
Page.perform_async(self.id)
瞧!就是这样。
我正在设计一个用户界面来上传用户列表(电子邮件、姓名等...),在该过程结束时,每个用户都会插入我的数据库并收到一封电子邮件.
处理此任务的后端 api 内置于 rails 上的 ruby。
目前对输入的大小没有限制,因此我想为 UI 用户提供一种在整个上传过程中取消剩余作业而不取消已发送作业的方法。
我还想在 GUI 上提供正在处理、已经完成的作业的实时状态。
此外,我想确保同时处理这些作业的作业数量是有限的,这样服务器上的其他用户就不会受到影响。
话虽如此...并且凭借我有限的后端/java脚本知识,我想我会做的是为每个用户(或者可能是一个分组)产生单独的 ajax 调用多个用户),使用 java 限制任何时候只有 X ajax 次调用可以同时进行 运行 (我希望这是可能的)并且每次调用时 returns我将更新 UI 以反映作业的状态,然后为下一组作业生成另一个,直到整个事情完成。如果 UI 用户希望取消,他们可以在已完成的作业保持完成。
这是明智的还是有更好的方法。
提前致谢
我使用 sidekiq 来完成这样的任务。它完全符合您的要求。
你设置了一些worker,它们是你服务器上的线程。然后,当 POST 或其他请求从 UI 传入时,您将每个请求作为 sidekiq 中的一项工作排队,并立即将 return 状态返回给浏览器,因此他们不必等待想知道是否会成功、永远挂起或被 Web 服务器超时。
稍后,作业将被异步处理。它可以更新数据库中的状态以进行报告。
这是在 sidekiq 下运行的 worker 示例:
class PageFetcher
include Sidekiq::Worker
def perform page_id
page = Page.find(page_id)
path = Page.absolute_path
# Do some big, long, error-prone thing with external depencies:
File.binwrite(path, open(page.source_url).read)
saved_size = File.size(path)
if page.expected_file_size != saved_size.to_s
bad_path = path + '.bad'
File.rename(path, bad_path)
# Raise an error, and sidekiq will automatically wait a while and try again later:
raise IOError, "Could not cache #{page.source_url} to #{path}. " +
"File size is #{saved_size}, expected #{page.file_size}. "
end
# update some status field, so this success can be reported:
page.make_status_cached!
# do something else that depends on this success:
page.notify_page_indexer
end
end
当您收到新请求时,创建一个新页面,然后按如下方式排队处理:
Page.perform_async(self.id)
瞧!就是这样。