[英]Redis variable in Sidekiq and Puma, thread safe?
我目前正在構建儀表板應用程序,但不確定我的解決方案是否正確。
目前,我有一個Sidekiq作業,每30秒運行一次。 該作業將數據保存到數據庫,並將新結果流式傳輸到每個儀表板。
我要解決的問題是從此工作開始,僅將數據(使用ActionCable)流式傳輸到“在線”儀表板。 (如果儀表板已在瀏覽器選項卡中打開)
解決方案是從我的DashboardChannel中保存Redis,例如:
class DashboardChannel < ApplicationCable::Channel
def subscribed
stream_from "dashboard:#{params['dashboard_id']}"
tabs_number = $redis.get("dashboard_#{params['dashboard_id']}_online").to_i
$redis.set("dashboard_#{params['dashboard_id']}_online", tabs_number+=1)
end
def unsubscribed
tabs_number = $redis.get("dashboard_#{params['dashboard_id']}_online").to_i
tabs_number-=1
if tabs_number == 0
$redis.del("dashboard_#{params['dashboard_id']}_online")
else
$redis.set("dashboard_#{params['dashboard_id']}_online", tabs_number)
end
end
end
我將在“ dashboard _#{DASHBOARD_ID} _online”鍵中打開的選項卡數保存下來。 保存選項卡的數量很重要,因為如果僅保存true / false(1/0),則在2個選項卡中打開儀表板,然后關閉其中的一個時,它將被標記為脫機。
在我的Sidekiq工作中,我有以下內容:
if Dashboard.online?(widget.dashboard_id) # returns true / false
ActionCable.server.broadcast "dashboard:#{widget.dashboard_id}",
{ widget_id: widget.id,
dashboard_id: widget.dashboard_id,
value: data_value.value,
recorded_at: data_value.recorded_at.strftime("%I:%M%p"),
in_bounds: data_value.in_bounds
}
end
在線方法app / models / dashboard.rb
def self.online?(dashboard_id)
!$redis.get("dashboard_#{dashboard_id}_online").nil?
end
在app / initializers / sidekiq.rb中
url = ENV["REDISTOGO_URL"] || "redis://localhost:6379/0"
uri = URI.parse(ENV["REDISTOGO_URL"] || "redis://localhost:6379/")
Sidekiq.configure_server do |config|
config.redis = { url: url, size: 4 }
end
Sidekiq.configure_client do |config|
config.redis = { url: url, size: 4 }
end
$redis = Redis.new(host: uri.host, port: uri.port, password: uri.password)
在app / initializers / redis.rb中
uri = URI.parse(ENV["REDISTOGO_URL"] || "redis://localhost:6379/")
$redis = Redis.new(host: uri.host, port: uri.port, password: uri.password)
# Remove all 'online dashboard' keys
keys = $redis.keys("dashboard_")
$redis.del(*keys) unless keys.empty?
我的問題:可以在Sidekiq作業的'app / initializers / sidekiq.rb'中使用聲明的'$ redis'全局變量嗎? 是線程保存的嗎?
目前,我還沒有找到使用這種代碼方法的工作流程問題,但是我擔心'$ redis'全局變量不應該位於Sidekiq Job的附近。
隨時添加代碼建議。 謝謝你,祝你有美好的一天!
實際上,安全線程沒有全局變量$ redis。 $ redis只是保持與redis服務器的連接。 Redis服務器是一個有關處理客戶端請求的單線程模型,因此它將以命令隊列的順序處理請求命令。
但是請注意,Sidekiq是多線程的。 如果您的同伴持有許多線程,並且每個線程都會將命令發送到Redis服務器。 將存在線程安全問題。 請閱讀redis交易以了解更多信息。
關於您的代碼,我不太了解。 但是有一點,如果您的DashboardChannel的訂閱者和取消訂閱者正在多線程或多處理中運行,您應該注意,壞事將會發生。
例如,如果操作按以下順序發生,
數字1 =客戶端1獲取密鑰
number2 =客戶端2獲取密鑰
客戶端1設置密鑰號1 + 1
客戶端2設置密鑰號2 +1
然后,您的密鑰將保留一個與實數相對的錯誤值。 如果是,請嘗試使用redis手表。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.