我想要一個執行緒本地(在 Rails 應用程式的背景關系中,每個請求),實體本地 var,例如假設我有一個可全域訪問的物件的實體。
module Event
def self.bus
@bus ||= Bus.new
end
end
該bus物件可以為每個請求設定元資料:
class Bus
def with_metadata(metadata, &block)
@metadata = metadata
block.call
end
# ...
end
問題在于,在執行緒環境中,例如 Puma 上的 Rails 應用程式,@metadata在不同執行緒(即請求)之間全域共享,因此如果元資料包含 IP 地址,例如,它僅對某些請求是不正確的。
我們可以使用Thread.current哪個是執行緒本地的:
class Bus
def with_metadata(metadata, &block)
Thread.current["with_metadata"] = metadata
block.call
ensure
Thread.current["with_metadata"] = nil
end
# ...
end
然而,這引入了一個問題,如果總線物件的另一個實體在同一個執行緒中初始化,即Event.bus和Bus.new,它們錯誤地共享“with_metadata”狀態。
我的想法是object_id在密鑰中包含:
class Bus
def with_metadata(metadata, &block)
Thread.current["#{object_id}_with_metadata"] = metadata
block.call
ensure
Thread.current["#{object_id}_with_metadata"] = nil
end
# ...
end
這聽起來合理嗎,是否有一種慣用的方式來擁有執行緒本地、實體本地 var?我不想依賴 Rails 或任何其他庫。
uj5u.com熱心網友回復:
Rails 依賴于concurrent-ruby gem,它為您提供了許多工具來處理多執行緒和并發環境。
具體來說,您可以在Concurrent::ThreadLocalVar此處使用該類:
class Bus
def initialize
@metadata = Concurrent::ThreadLocalVar.new
end
def metadata
@metadata.value
end
def with_metadata(metadata, &block)
@metadata.value = metadata
yield
ensure
@metadata.value = nil
end
# ...
end
有關更多使用示例,請參閱上面鏈接的檔案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/460555.html
標籤:红宝石
上一篇:匹配和包括?方法
下一篇:通過物件ID維護RubySet
