2020 年 08 月討論 === ## Cindy https://hackmd.io/@cindyliu923/HJ0vRHZmD ## 蒼時 ## 詹昇 https://hackmd.io/@5Qs45kiLTZGZg3r154VjPQ/HJXK3zCfP#/ ## 參考資料 * https://pdabrowski.com/articles/how-sidekiq-really-works * https://draveness.me/sidekiq/ ## Sidekiq 與 Redis ### Background Job 在軟體開發中我們經常會把一些需要長時間處理的任務放到背景來執行,一般來說我們會使用 Queue 的機制來將任務記錄下來,並且在有空閑的 Worker 時取出任務來處理。 > 個人認為在電腦多工的概念上是類似的,不過在這邊我們是為了讓應用程式能將過長且不需要即時回應的任務延後處理,實際上也就是「非同步」的概念。 ### Ruby 的簡易實作 在 Ruby 的 `thread` 標準函式庫中已經提供了 `Queue` 物件,內置了一個鎖(Lock)來確保寫入跟取出不會有競爭的情況存在,因此我們可以很簡單的利用 Thread 實現一個單機版本的 Sidekiq。 ```ruby class Task def initialize(*args, &block) @args = args @proc = block end def perform @proc.call @args end end class Worker def initialize(idx, queue) @idx = idx @thread = nil @queue = queue end def run! return unless @thread.nil? @thread = Thread.new do loop do task = @queue.pop ret = task.perform puts "Worker #{@idx} run: #{ret}" end end end end queue = Queue.new workers = 3.times.map { |idx| Worker.new(idx, queue) } workers.each(&:run!) count = 0 loop do 4.times do task = Task.new(count) { |args| "Task run #{args[0]}" } count += 1 queue << task end sleep 1 end ``` ### 使用 Redis 保存 Queue 我們可以利用 Redis 的 LIST 功能把任務的資訊記錄到 Redis 裡面,並且利用 `RPUSH` / `BLPOP` 指令來取出資料 ```ruby require 'redis' require 'json' class RedisQueue def initialize @conn = Redis.new end def pop _, count = @conn.blpop 'example-queue' # 以 Blocking 方式取出資料,如果 LIST 是空的則進入 Blocking 狀態 CountTask.new(count.to_i) end def <<(task) @conn.rpush 'example-queue', task.count end end class CountTask attr_reader :count def initialize(count) @count = count end def perform "Task run in #{count}" end end class Worker def initialize(idx) @idx = idx @thread = nil @queue = RedisQueue.new # 因為共用 Connection 會 Blocking 所有人所以先各自建立連線 end def run! return unless @thread.nil? @thread = Thread.new do loop do task = @queue.pop ret = task.perform puts "Worker #{@idx} run: #{ret}" end end end end queue = RedisQueue.new workers = 3.times.map { |idx| Worker.new(idx) } workers.each(&:run!) count = 0 loop do 4.times do task = CountTask.new(count) count += 1 queue << task end sleep 1 end ```
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up