- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在写一个工作人员将很多用户添加到一个组中。我想知道是运行一个拥有所有用户的大任务更好,还是像 100 个用户那样批量运行,或者每个任务一个一个地运行。
目前这是我的代码
class AddUsersToGroupWorker
include Sidekiq::Worker
sidekiq_options :queue => :group_utility
def perform(store_id, group_id, user_ids_to_add)
begin
store = Store.find store_id
group = Group.find group_id
rescue ActiveRecord::RecordNotFound => e
Airbrake.notify e
return
end
users_to_process = store.users.where(id: user_ids_to_add)
.where.not(id: group.user_ids)
group.users += users_to_process
users_to_process.map(&:id).each do |user_to_process_id|
UpdateLastUpdatesForUserWorker.perform_async store.id, user_to_process_id
end
end
end
也许在我的方法中加入这样的东西会更好:
def add_users
users_to_process = store.users.where(id: user_ids_to_add)
.where.not(id: group.user_ids)
users_to_process.map(&:id).each do |user_to_process_id|
AddUserToGroupWorker.perform_async group_id, user_to_process_id
UpdateLastUpdatesForUserWorker.perform_async store.id, user_to_process_id
end
end
但是有那么多find
请求。你怎么看?
如果需要(例如批处理),我有一个 sidekig pro 许可证。
最佳答案
这是我的想法。
<强>1。执行单个 SQL 查询而不是 N 个查询
这一行:group.users += users_to_process
可能会产生 N 个 SQL 查询(其中 N 是 users_to_process.count)。我假设您在用户和组之间有多对多连接(使用 user_groups
连接表/模型),因此您应该使用一些 Mass inserting data technique :
users_to_process_ids = store.users.where(id: user_ids_to_add)
.where.not(id: group.user_ids)
.pluck(:id)
sql_values = users_to_process_ids.map{|i| "(#{i.to_i}, #{group.id.to_i}, NOW(), NOW())"}
Group.connection.execute("
INSERT INTO groups_users (user_id, group_id, created_at, updated_at)
VALUES #{sql_values.join(",")}
")
是的,它是原始 SQL。而且它很快。
<强>2。用户 pluck(:id)
而不是 map(&:id)
pluck
更快,因为:
做 SQL 很便宜。创建 Ruby 对象非常昂贵。
<强>3。使用水平并行化而不是垂直并行化
我在这里的意思是,如果您需要为十几个记录执行顺序任务 A -> B -> C
,有两种主要的拆分工作的方法:
AWorker
执行A(1)
、A(2)
、A(3)
; BWorker
做B(1)
等; CWorker
完成所有 C(i)
工作;UniversalWorker
执行 A(1)+B(1)+C(1)
。使用后一种(水平)方式。
这是经验的陈述,而不是从某些理论的角度(两种方式都可行)。
为什么要这样做?
B
和 C
worker 只会浪费 RAM,而您的 A
worker 会完成这项工作。然后你的 A
和 C
将浪费 RAM,而 B
正在工作。等等。如果您进行水平分割,您的资源消耗将自行消失。将该建议应用于您的具体情况:对于初学者,不要在另一个异步任务中调用 perform_async
。
<强>4。批量处理
回答您最初的问题 – 是的,分批处理。创建和管理异步任务本身会占用一些资源,因此无需创建太多。
TL;DR 所以最后,您的代码可能如下所示:
# model code
BATCH_SIZE = 100
def add_users
users_to_process_ids = store.users.where(id: user_ids_to_add)
.where.not(id: group.user_ids)
.pluck(:id)
# With 100,000 users performance of this query should be acceptable
# to make it in a synchronous fasion
sql_values = users_to_process_ids.map{|i| "(#{i.to_i}, #{group.id.to_i}, NOW(), NOW())"}
Group.connection.execute("
INSERT INTO groups_users (user_id, group_id, created_at, updated_at)
VALUES #{sql_values.join(",")}
")
users_to_process_ids.each_slice(BATCH_SIZE) do |batch|
AddUserToGroupWorker.perform_async group_id, batch
end
end
# add_user_to_group_worker.rb
def perform(group_id, user_ids_to_add)
group = Group.find group_id
# Do some heavy load with a batch as a whole
# ...
# ...
# If nothing here is left, call UpdateLastUpdatesForUserWorker from the model instead
user_ids_to_add.each do |id|
# do it synchronously – we already parallelized the job
# by splitting it in slices in the model above
UpdateLastUpdatesForUserWorker.new.perform store.id, user_to_process_id
end
end
关于ruby - Sidekiq 的大任务或多个小任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32198647/
我想使用 rails 控制台重新启动所有失败的作业。有没有办法做到这一点?我可以使用以下方法获取工作列表: require 'sidekiq/api' Sidekiq::Queue.new("mail
我想使用 Datadog 来监控一些后台作业的队列长度。 基本上我需要知道 Sidekiq 中代表队列的键的名称 ,以便我可以按照此处所述对其进行监控: https://docs.datadoghq.
我将 Sidekiq 与 Rails 一起使用,返回的并发值似乎是错误的。 Sidekiq.options[:concurrency] 返回 10 而不是 3,这是我的 config/sidekiq.
从Rails API中,我发现ActiveJob可以retry_job间隔: my_job_instance.enqueue my_job_instance.enqueue wait: 5.minut
我正在一个作业中进行一些处理,最终执行一个外部 shell 命令。该命令正在执行需要数小时才能完成的脚本。 问题是在我使用 spawn 启动脚本后和 detach如果我使用 kill -15 信号关闭
我有一个使用 Capistrano 部署的 Rails 3 应用程序。我最近添加了 Sidekiq。它在我的开发中运行良好。我同时主持 staging和 preview在同一台服务器上,它的预览无法正
我有一个简单的工作线程正在访问其自己的队列的大小: 需要“sidekiq/api” class TestWorker include Sidekiq::Worker def perform(*
我在我的 Rails 应用程序中使用 sidekiq。默认情况下,任何人都可以通过在 url 后附加“/sidekiq”来访问 Sidekiq。我只想用密码保护/验证 sidekiq 部分。我该怎么做
我正在在线阅读一些教程,这些教程告诉我们将 ActiveJob 与 Sidekiq 结合使用。但我不知道我们为什么要这样做。我看到 Sidekiq 具有 ActiveJob 的所有功能。 此外,在 S
我猴子修补了我的用户类(由设计支持)以像这样使用 ActiveJob: class User ActionMailer::DeliveryJob, :args=>["Devise::Mailer",
我有 sidekiq 作业对多种类型的资源进行处理。但是,对于特定类型的资源,例如:资源 X,我需要确保在任何给定时间只有一个 sidekiq 作业可以处理该特定资源。 例如,如果我有 3 个 sid
在过去的一年里,我对我的一项工作的流程进行了大量更改。诸如从相应模型上的 after_commit 而不是 after_create 触发它,以及清理逻辑和覆盖极端情况 我在我的 Heroku Rub
我看到this在 Sidekiq 官方 wiki 中,ActiveJob 会慢得多。 但它是在 2018 年 3 月根据此 issue 基于 Rails 4.2 和 Sidekiq 5.1.1 提到的
我使用 Rails 4 默认测试框架并编写了一些测试,这些测试也希望 Sidekiq 在“后台”做一些工作。但是当我运行 rake test 时,我的测试结果看起来像这样: .............
我们几周前在我们的系统中添加了监控用户事件,如下所示: class ApplicationController < ActionController::Base before_filter :lo
我正在运行 7 个 sidekiq 进程(货币设置为 40)和一个乘客网络服务器,连接到 postgres 数据库。 Rails 池设置设置为 100,postgres max_connectio
我第一次在 Rails 应用程序中使用 Sidekiq。这也是我第一次使用Redis。 我见过几个示例(Here、here、here),其中 initializers/sidekiq.rb 包含以下几
我刚开始使用 sidekiq 和 redis,我试图让 sidekiq 在 Heroku 上运行,但每次我部署 Rails 4 应用程序时它似乎都会崩溃。我在 Papertrail 中收到此错误: M
我有一个要求,我应该能够每秒运行 100 个 sidekiq 作业。 我将服务器容量增加到 8 个 CPU 并创建了 4 个 sidekiq 进程,但它仍然每分钟服务 50 个作业。 我不确定我在哪里
我在 Sidekiq 中有两种队列:“default/low”——满足网络请求和“background_queue”——运行后台进程,比如获取推文。我想在不同的 dyno 上运行“background
我是一名优秀的程序员,十分优秀!