lib/sidekiq-benchmark/worker.rb
# frozen_string_literal: true
module Sidekiq
module Benchmark
module Worker
def benchmark(options = {})
@benchmark ||= Benchmark.new self, benchmark_redis_type_key, options
if block_given?
yield @benchmark
@benchmark.finish
end
@benchmark
end
def benchmark_redis_type_key
@benchmark_redis_type_key ||= self.class.name.gsub('::', '_').downcase
end
class Benchmark
attr_reader :metrics, :start_time, :finish_time, :redis_keys
def initialize(worker, redis_key, options)
@metrics = {}
@worker = worker
@options = options
@start_time = Time.now
@redis_keys =
%i[total stats].reduce({}) do |m, e|
m[e] = "#{REDIS_NAMESPACE}:#{redis_key}:#{e}"
m
end
set_redis_key redis_key
end
def finish
@finish_time = Time.now
self[:job_time] = finish_time - start_time
save
end
def measure(name)
t0 = Time.now
ret = yield
t1 = Time.now
self[name] ||= 0.0
self[name] += t1 - t0
Sidekiq.logger.info "Benchmark #{name}: #{t1 - t0} sec." if @options[:log]
ret
end
alias_method :bm, :measure
def call(name, *args)
measure(name) { @worker.send(name, *args) }
end
def []=(name, value)
@metrics[name] = value.to_f
end
def [](name)
@metrics[name]
end
def set_redis_key(key)
Sidekiq.redis do |conn|
conn.sadd TYPES_KEY, key
conn.expire TYPES_KEY, REDIS_KEYS_TTL
end
end
def save
job_time_key = @metrics[:job_time].round(1)
Sidekiq.redis do |conn|
conn.multi do |transaction|
@metrics.each do |key, value|
transaction.hincrbyfloat redis_keys[:total], key, value
end
transaction.hincrby redis_keys[:stats], job_time_key, 1
transaction.hsetnx redis_keys[:total], "start_time", start_time.to_s
transaction.hset redis_keys[:total], "finish_time", finish_time.to_s
transaction.expire redis_keys[:stats], REDIS_KEYS_TTL
transaction.expire redis_keys[:total], REDIS_KEYS_TTL
end
end
end
def method_missing(name, *args, &block)
if block_given?
measure(name, &block)
self[name]
else
self[name] = args[0]
end
end
end
end
end
end