Module: DeadBro::Collectors::SampleStore

Defined in:
lib/dead_bro/collectors/sample_store.rb

Overview

SampleStore provides a tiny, best-effort persistence layer for time-series samples (CPU, network, etc.) between runs.

It prefers Redis via Sidekiq when available and otherwise falls back to a JSON file in /tmp. All failures are swallowed and simply result in nil being returned from #load.

Class Method Summary collapse

Class Method Details

.file_path(key) ⇒ Object



100
101
102
103
104
105
# File 'lib/dead_bro/collectors/sample_store.rb', line 100

def file_path(key)
  digest = Digest::SHA256.hexdigest(key.to_s)[0, 16]
  File.join(Dir.tmpdir, "dead_bro_metrics_#{digest}.json")
rescue
  "/tmp/dead_bro_metrics_#{key.to_s.gsub(/[^a-zA-Z0-9]/, "_")}.json"
end

.load(key) ⇒ Object



18
19
20
21
22
# File 'lib/dead_bro/collectors/sample_store.rb', line 18

def load(key)
  load_from_redis(key) || load_from_file(key)
rescue
  nil
end

.load_from_file(key) ⇒ Object



57
58
59
60
61
62
63
64
65
66
# File 'lib/dead_bro/collectors/sample_store.rb', line 57

def load_from_file(key)
  path = file_path(key)
  return nil unless File.file?(path)

  File.open(path, "r") do |f|
    JSON.parse(f.read)
  end
rescue
  nil
end

.load_from_redis(key) ⇒ Object



36
37
38
39
40
41
42
43
44
45
# File 'lib/dead_bro/collectors/sample_store.rb', line 36

def load_from_redis(key)
  return nil unless defined?(Sidekiq) && Sidekiq.respond_to?(:redis)

  raw = Sidekiq.redis { |r| r.get(redis_key(key)) }
  return nil unless raw

  JSON.parse(raw)
rescue
  nil
end

.redis_key(key) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
# File 'lib/dead_bro/collectors/sample_store.rb', line 88

def redis_key(key)
  env = DeadBro.env
  host = begin
    require "socket"
    Socket.gethostname
  rescue
    "unknown"
  end

  "dead_bro:metrics:#{env}:#{host}:#{key}"
end

.save(key, data) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
# File 'lib/dead_bro/collectors/sample_store.rb', line 24

def save(key, data)
  save_to_redis(key, data)
rescue
  # If Redis is unavailable or fails, fall back to file-based storage
ensure
  begin
    save_to_file(key, data)
  rescue
    # Completely best-effort
  end
end

.save_to_file(key, data) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/dead_bro/collectors/sample_store.rb', line 68

def save_to_file(key, data)
  path = file_path(key)
  dir = File.dirname(path)
  Dir.mkdir(dir) unless Dir.exist?(dir)

  File.open(path, File::RDWR | File::CREAT, 0o600) do |f|
    f.flock(File::LOCK_EX)
    f.rewind
    f.truncate(0)
    f.write(JSON.dump(data))
  ensure
    begin
      f.flock(File::LOCK_UN)
    rescue
    end
  end
rescue
  # Best-effort only
end

.save_to_redis(key, data) ⇒ Object



47
48
49
50
51
52
53
54
55
# File 'lib/dead_bro/collectors/sample_store.rb', line 47

def save_to_redis(key, data)
  return unless defined?(Sidekiq) && Sidekiq.respond_to?(:redis)

  Sidekiq.redis do |r|
    r.set(redis_key(key), JSON.dump(data), ex: 300) # keep for 5 minutes
  end
rescue
  # Best-effort only
end