-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add listener_address as Instance attributes of Promenade::Raindrops::Stats Fix guard clauses πββοΈ Update dev dependencies Update Bundler version
- Loading branch information
1 parent
328463b
commit d2db529
Showing
9 changed files
with
277 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
require "singleton" | ||
|
||
module Promenade | ||
class PeriodicStats | ||
include Singleton | ||
|
||
def initialize | ||
@thread_stopped = true | ||
@thread = nil | ||
end | ||
|
||
def self.configure(frequency:, logger: nil, &block) | ||
instance.configure(frequency: frequency, logger: logger, &block) | ||
end | ||
|
||
def self.start | ||
instance.start | ||
end | ||
|
||
def self.stop | ||
instance.stop | ||
end | ||
|
||
def configure(frequency:, logger: nil, &block) | ||
@frequency = frequency | ||
@block = block | ||
@logger = logger | ||
end | ||
|
||
def start | ||
stop | ||
|
||
@thread_stopped = false | ||
@thread = Thread.new do | ||
while active? | ||
block.call | ||
sleep(frequency) # Ensure the sleep is inside the loop | ||
end | ||
end | ||
rescue StandardError => e | ||
logger&.error("Promenade: Error in periodic stats: #{e.message}") | ||
end | ||
|
||
def stop | ||
return unless thread | ||
|
||
if started? | ||
@thread_stopped = true | ||
thread.kill | ||
thread.join | ||
end | ||
|
||
@thread = nil | ||
end | ||
|
||
private | ||
|
||
attr_reader :logger, :frequency, :block, :thread, :thread_stopped | ||
|
||
def started? | ||
thread&.alive? | ||
end | ||
|
||
def active? | ||
!thread_stopped | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
require "promenade/raindrops/stats" | ||
|
||
module Promenade | ||
module Pitchfork | ||
class Stats | ||
Promenade.gauge :pitchfork_workers_count do | ||
doc "Number of workers configured" | ||
end | ||
|
||
Promenade.gauge :pitchfork_live_workers_count do | ||
doc "Number of live / booted workers" | ||
end | ||
|
||
Promenade.gauge :pitchfork_capacity do | ||
doc "Number of workers that are currently idle" | ||
end | ||
|
||
Promenade.gauge :pitchfork_busy_percent do | ||
doc "Percentage of workers that are currently busy" | ||
end | ||
|
||
def initialize | ||
return unless defined?(::Pitchfork) && defined?(::Pitchfork::Info) | ||
|
||
@workers_count = ::Pitchfork::Info.workers_count | ||
@live_workers_count = ::Pitchfork::Info.live_workers_count | ||
|
||
raindrops_stats = Raindrops::Stats.new | ||
|
||
@active_workers = raindrops_stats.active_workers || 0 | ||
@queued_requests = raindrops_stats.queued_requests || 0 | ||
end | ||
|
||
def instrument | ||
Promenade.metric(:pitchfork_workers_count).set({}, workers_count) | ||
Promenade.metric(:pitchfork_live_workers_count).set({}, live_workers_count) | ||
Promenade.metric(:pitchfork_capacity).set({}, capacity) | ||
Promenade.metric(:pitchfork_busy_percent).set({}, busy_percent) | ||
end | ||
|
||
def self.instrument | ||
new.instrument | ||
end | ||
|
||
private | ||
|
||
attr_reader :workers_count, :live_workers_count, :active_workers, :queued_requests | ||
|
||
def capacity | ||
return 0 if live_workers_count.nil? || live_workers_count == 0 | ||
|
||
live_workers_count - active_workers | ||
end | ||
|
||
def busy_percent | ||
return 0 if live_workers_count == 0 | ||
|
||
(active_workers.to_f / live_workers_count) * 100 | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
begin | ||
require "raindrops" | ||
rescue LoadError | ||
# No raindrops available, dont do anything | ||
end | ||
|
||
module Promenade | ||
module Raindrops | ||
Promenade.gauge :rack_active_workers do | ||
doc "Number of active workers in the Application Server" | ||
end | ||
|
||
Promenade.gauge :rack_queued_requests do | ||
doc "Number of requests waiting to be processed by the Application Server" | ||
end | ||
|
||
class Stats | ||
attr_reader :active_workers, :queued_requests, :listener_address | ||
|
||
def initialize(listener_address: nil) | ||
return unless defined?(::Raindrops) | ||
return unless defined?(::Raindrops::Linux.tcp_listener_stats) | ||
|
||
@listener_address = listener_address || "127.0.0.1:#{ENV.fetch('PORT', 3000)}" | ||
|
||
stats = ::Raindrops::Linux.tcp_listener_stats([@listener_address])[@listener_address] | ||
|
||
@active_workers = stats.active | ||
@queued_requests = stats.queued | ||
end | ||
|
||
def instrument | ||
Promenade.metric(:rack_active_workers).set({}, active_workers) | ||
Promenade.metric(:rack_queued_requests).set({}, queued_requests) | ||
end | ||
|
||
def self.instrument(listener_address: nil) | ||
new(listener_address: listener_address).instrument | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
require "spec_helper" | ||
|
||
RSpec.describe Promenade::PeriodicStats do | ||
describe "#start" do | ||
it "executes the block at the specified frequency" do | ||
counter = 0 | ||
Promenade::PeriodicStats.configure(frequency: 0.1) { counter += 1 } | ||
Promenade::PeriodicStats.start | ||
|
||
sleep(0.2) | ||
Promenade::PeriodicStats.stop | ||
|
||
expect(counter).to be > 1 | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
require "spec_helper" | ||
require "promenade/pitchfork/stats" | ||
|
||
RSpec.describe Promenade::Pitchfork::Stats do | ||
let(:pitchfork_info) { class_double("Pitchfork::Info") } | ||
let(:raindrops_stats) { instance_double("Promenade::Raindrops::Stats", active_workers: 6, queued_requests: 2) } | ||
|
||
before do | ||
stub_const("Pitchfork::Info", pitchfork_info) | ||
allow(pitchfork_info).to receive(:workers_count).and_return(10) | ||
allow(pitchfork_info).to receive(:live_workers_count).and_return(8) | ||
|
||
allow(Promenade::Raindrops::Stats).to receive(:new).and_return(raindrops_stats) | ||
end | ||
|
||
describe "#instrument" do | ||
let(:metric) { instance_double("Promenade::Metric") } | ||
|
||
before do | ||
allow(Promenade).to receive(:metric).and_return(metric) | ||
allow(metric).to receive(:set) | ||
end | ||
|
||
it "sets the metrics correctly" do | ||
stats = Promenade::Pitchfork::Stats.new | ||
|
||
expect(Promenade).to receive(:metric).with(:pitchfork_workers_count).and_return(metric) | ||
expect(Promenade).to receive(:metric).with(:pitchfork_live_workers_count).and_return(metric) | ||
expect(Promenade).to receive(:metric).with(:pitchfork_capacity).and_return(metric) | ||
expect(Promenade).to receive(:metric).with(:pitchfork_busy_percent).and_return(metric) | ||
|
||
expect(metric).to receive(:set).with({}, 10) | ||
expect(metric).to receive(:set).with({}, 8) | ||
expect(metric).to receive(:set).with({}, 2) | ||
expect(metric).to receive(:set).with({}, 75.0) | ||
|
||
stats.instrument | ||
end | ||
end | ||
|
||
describe ".instrument" do | ||
it "calls the instance method instrument" do | ||
stats_instance = instance_double("Promenade::Pitchfork::Stats") | ||
allow(Promenade::Pitchfork::Stats).to receive(:new).and_return(stats_instance) | ||
allow(stats_instance).to receive(:instrument) | ||
|
||
Promenade::Pitchfork::Stats.instrument | ||
|
||
expect(stats_instance).to have_received(:instrument) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
require "spec_helper" | ||
require "promenade/raindrops/stats" | ||
|
||
RSpec.describe Promenade::Raindrops::Stats do | ||
let(:listen_stats) { instance_double("Raindrops::Linux::ListenStats", active: 1, queued: 1) } | ||
let(:listener_address) { "127.0.0.1:#{ENV.fetch('PORT', 3000)}" } | ||
|
||
before do | ||
allow(Raindrops::Linux).to receive(:tcp_listener_stats).and_return({ listener_address => listen_stats }) | ||
end | ||
|
||
describe "#instrument" do | ||
let(:metric) { instance_double("Promenade::Metric") } | ||
|
||
before do | ||
allow(Promenade).to receive(:metric).and_return(metric) | ||
allow(metric).to receive(:set) | ||
end | ||
|
||
it "sets the metrics correctly" do | ||
stats = Promenade::Raindrops::Stats.new | ||
|
||
expect(Promenade).to receive(:metric).with(:rack_active_workers).and_return(metric) | ||
expect(Promenade).to receive(:metric).with(:rack_queued_requests).and_return(metric) | ||
|
||
expect(metric).to receive(:set).with({}, 1) | ||
expect(metric).to receive(:set).with({}, 1) | ||
|
||
stats.instrument | ||
end | ||
end | ||
end |