neetodeploy-autoscale 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/neetodeploy/autoscale/config.rb +7 -1
- data/lib/neetodeploy/autoscale/rails/metrics.rb +30 -0
- data/lib/neetodeploy/autoscale/rails/metrics_collector.rb +54 -0
- data/lib/neetodeploy/autoscale/rails/metrics_store.rb +27 -0
- data/lib/neetodeploy/autoscale/rails/middleware.rb +30 -0
- data/lib/neetodeploy/autoscale/rails/railtie.rb +17 -0
- data/lib/neetodeploy/autoscale/rails.rb +7 -0
- data/lib/neetodeploy/autoscale/reporter.rb +32 -3
- data/lib/neetodeploy/autoscale/sidekiq/metrics_collector.rb +88 -0
- data/lib/neetodeploy/autoscale/sidekiq.rb +3 -0
- data/lib/neetodeploy/autoscale/version.rb +1 -1
- data/lib/neetodeploy-autoscale.rb +46 -9
- metadata +11 -8
- data/lib/neetodeploy/autoscale/metrics.rb +0 -26
- data/lib/neetodeploy/autoscale/metrics_collector.rb +0 -53
- data/lib/neetodeploy/autoscale/metrics_store.rb +0 -25
- data/lib/neetodeploy/autoscale/middleware.rb +0 -28
- data/lib/neetodeploy/autoscale/railtie.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27447ab3dd1a86114502dba20ac472fdbbc5de7c56e6d65bb9f4b5790c24a6cd
|
4
|
+
data.tar.gz: 8124289ad97a7ea6742af785d5c6183e2f2238faa65c7fb38a1275fe58fdeafc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 77e3bb73219f39f717511e3b9f860daf6cbc610b26f656061312a54095c2d6d62e894c8a44027c35fff37948edcada469bf4bfc5a33ede5deec5917320a9a1e2
|
7
|
+
data.tar.gz: f40763ca2219295b1a64c0f76addeeb8539493be1757bdec45ef7830f6379e1b741903ae5acc3894510a37d5dfd600103b25cabfabee2e960bf441332b7fd334
|
@@ -2,10 +2,12 @@ module Neetodeploy
|
|
2
2
|
class Config
|
3
3
|
include Singleton
|
4
4
|
|
5
|
-
attr_accessor :disable_auto_scale_gem, :
|
5
|
+
attr_accessor :disable_auto_scale_gem, :disable_sidekiq_metrics, :app_name, :metrics_server_url,
|
6
|
+
:metrics_server_auth_token, :report_interval_seconds
|
6
7
|
|
7
8
|
def initialize
|
8
9
|
@disable_auto_scale_gem = ENV["DISABLE_NEETO_DEPLOY_AUTOSCALE"]
|
10
|
+
@disable_sidekiq_metrics = ENV["DISABLE_NEETO_DEPLOY_SIDEKIQ_METRICS"]
|
9
11
|
@app_name = ENV["NEETODEPLOY_APP_NAME"]
|
10
12
|
@metrics_server_url = "http://nd-queue-time-exporter-web-deployment:3000/metrics"
|
11
13
|
@metrics_server_auth_token = "K0An3O3MSyEEMTCnRd1IHgGjdGQkzy"
|
@@ -15,5 +17,9 @@ module Neetodeploy
|
|
15
17
|
def gem_disabled?
|
16
18
|
disable_auto_scale_gem == "true"
|
17
19
|
end
|
20
|
+
|
21
|
+
def sidekiq_metrics_disabled?
|
22
|
+
disable_sidekiq_metrics == "true"
|
23
|
+
end
|
18
24
|
end
|
19
25
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "neetodeploy/autoscale/config"
|
4
|
+
|
5
|
+
module Neetodeploy
|
6
|
+
module Rails
|
7
|
+
class Metrics
|
8
|
+
def initialize(env, config = Config.instance)
|
9
|
+
@config = config
|
10
|
+
@request_start_header = env["HTTP_X_REQUEST_START"].to_i
|
11
|
+
@network_time = env["puma.request_body_wait"].to_i
|
12
|
+
end
|
13
|
+
|
14
|
+
def ignore?
|
15
|
+
@config.gem_disabled?
|
16
|
+
end
|
17
|
+
|
18
|
+
def queue_time
|
19
|
+
return if @request_start_header.zero?
|
20
|
+
|
21
|
+
time_now = Time.now.to_f * 1000
|
22
|
+
|
23
|
+
queue_time = (time_now - @request_start_header).round
|
24
|
+
queue_time -= @network_time
|
25
|
+
|
26
|
+
queue_time.positive? ? queue_time : nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
require "neetodeploy/autoscale/rails/metrics_store"
|
5
|
+
require "neetodeploy/autoscale/reporter"
|
6
|
+
require "neetodeploy/autoscale/logger"
|
7
|
+
|
8
|
+
module Neetodeploy
|
9
|
+
module Rails
|
10
|
+
class MetricsCollector
|
11
|
+
include Singleton
|
12
|
+
include NeetoDeploy::Logger
|
13
|
+
|
14
|
+
def self.start
|
15
|
+
instance.start! unless instance.running?
|
16
|
+
end
|
17
|
+
|
18
|
+
def start!
|
19
|
+
logger.info("Starting background worker to collect metrics")
|
20
|
+
@pid = Process.pid
|
21
|
+
start_thread_with_collector_loop
|
22
|
+
end
|
23
|
+
|
24
|
+
def stop!
|
25
|
+
@thread&.terminate
|
26
|
+
@thread = nil
|
27
|
+
@pid = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def running?
|
31
|
+
@pid == Process.pid and @thread.alive?
|
32
|
+
end
|
33
|
+
|
34
|
+
def start_thread_with_collector_loop(config = Config.instance)
|
35
|
+
@thread = Thread.new do
|
36
|
+
metrics_store = MetricsStore.instance
|
37
|
+
loop do
|
38
|
+
run_metrics_collection(metrics_store)
|
39
|
+
multiplier = 1 - (rand / 4)
|
40
|
+
sleep config.report_interval_seconds * multiplier
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def run_metrics_collection(metrics_store)
|
46
|
+
data = metrics_store.flush
|
47
|
+
return if data.empty?
|
48
|
+
|
49
|
+
average_queue_time = data.sum / data.size
|
50
|
+
Reporter.new(average_queue_time, "queue_time", "web").report
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
|
5
|
+
module Neetodeploy
|
6
|
+
module Rails
|
7
|
+
class MetricsStore
|
8
|
+
include Singleton
|
9
|
+
|
10
|
+
attr_reader :metrics
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@metrics = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def push(queue_time)
|
17
|
+
@metrics << queue_time
|
18
|
+
end
|
19
|
+
|
20
|
+
def flush
|
21
|
+
result = @metrics
|
22
|
+
@metrics = []
|
23
|
+
result
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "net/http"
|
4
|
+
require "time"
|
5
|
+
require "neetodeploy/autoscale/rails/metrics"
|
6
|
+
require "neetodeploy/autoscale/rails/metrics_store"
|
7
|
+
require "neetodeploy/autoscale/rails/metrics_collector"
|
8
|
+
|
9
|
+
module Neetodeploy
|
10
|
+
module Rails
|
11
|
+
class Middleware
|
12
|
+
def initialize(app)
|
13
|
+
@app = app
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
metrics = Metrics.new(env)
|
18
|
+
queue_time = metrics.queue_time unless metrics.ignore?
|
19
|
+
MetricsCollector.start
|
20
|
+
|
21
|
+
if queue_time
|
22
|
+
store = MetricsStore.instance
|
23
|
+
store.push queue_time
|
24
|
+
end
|
25
|
+
|
26
|
+
@app.call(env)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "neetodeploy/autoscale/rails/middleware"
|
4
|
+
module Neetodeploy
|
5
|
+
module Rails
|
6
|
+
class Railtie < ::Rails::Railtie
|
7
|
+
initializer "neetodeploy.Neetodeploy.middleware" do |app|
|
8
|
+
app.middleware.insert_before Rack::Runtime, Neetodeploy::Rails::Middleware
|
9
|
+
end
|
10
|
+
|
11
|
+
config.after_initialize do
|
12
|
+
Neetodeploy::Rails::MetricsCollector.start
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "neetodeploy/autoscale/rails/metrics"
|
4
|
+
require "neetodeploy/autoscale/rails/metrics_store"
|
5
|
+
require "neetodeploy/autoscale/rails/metrics_collector"
|
6
|
+
require "neetodeploy/autoscale/rails/middleware"
|
7
|
+
require "neetodeploy/autoscale/rails/railtie"
|
@@ -3,19 +3,41 @@
|
|
3
3
|
require "net/http"
|
4
4
|
require "time"
|
5
5
|
require "neetodeploy/autoscale/config"
|
6
|
+
require "neetodeploy/autoscale/logger"
|
6
7
|
|
7
8
|
module Neetodeploy
|
8
9
|
class Reporter
|
10
|
+
include NeetoDeploy::Logger
|
9
11
|
|
10
|
-
def initialize(queue_time, config = Config.instance
|
12
|
+
def initialize(queue_time, metric_name, process_type, queue_name = nil, config = Config.instance)
|
11
13
|
@queue_time = queue_time.to_i
|
12
14
|
@config = config
|
15
|
+
@metric_name = metric_name
|
16
|
+
@queue_name = queue_name
|
17
|
+
@process_type = process_type
|
13
18
|
end
|
14
19
|
|
15
20
|
def report
|
16
|
-
|
17
|
-
|
21
|
+
params = common_params
|
22
|
+
params[:queue_name] = @queue_name if @queue_name
|
23
|
+
url = build_url(params)
|
24
|
+
logger.info("Reporting average queue time for #{@process_type} dyno: #{@queue_time}")
|
18
25
|
|
26
|
+
post_request(url)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def common_params
|
32
|
+
{
|
33
|
+
app_name: @config.app_name,
|
34
|
+
queue_time: @queue_time,
|
35
|
+
metric_name: @metric_name,
|
36
|
+
process_type: @process_type
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def post_request(url)
|
19
41
|
post = Net::HTTP::Post.new(url)
|
20
42
|
post["AuthToken"] = @config.metrics_server_auth_token
|
21
43
|
|
@@ -23,5 +45,12 @@ module Neetodeploy
|
|
23
45
|
http.request(post)
|
24
46
|
end
|
25
47
|
end
|
48
|
+
|
49
|
+
def build_url(params = {})
|
50
|
+
exporter_url = URI.parse(@config.metrics_server_url)
|
51
|
+
exporter_url.query = URI.encode_www_form(params)
|
52
|
+
|
53
|
+
exporter_url
|
54
|
+
end
|
26
55
|
end
|
27
56
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
require "neetodeploy/autoscale/reporter"
|
5
|
+
require "neetodeploy/autoscale/logger"
|
6
|
+
require "neetodeploy/autoscale/config"
|
7
|
+
require "sidekiq/api"
|
8
|
+
|
9
|
+
module Neetodeploy
|
10
|
+
module Sidekiq
|
11
|
+
class MetricsCollector
|
12
|
+
include Singleton
|
13
|
+
include NeetoDeploy::Logger
|
14
|
+
|
15
|
+
def self.start
|
16
|
+
instance.start! unless instance.running?
|
17
|
+
end
|
18
|
+
|
19
|
+
def start!
|
20
|
+
logger.info("Starting Sidekiq metrics collector")
|
21
|
+
@pid = Process.pid
|
22
|
+
start_thread_with_collector_loop
|
23
|
+
end
|
24
|
+
|
25
|
+
def stop!
|
26
|
+
@pid = nil # Set pid to nil first to prevent restart
|
27
|
+
@thread&.terminate
|
28
|
+
@thread = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def running?
|
32
|
+
@pid == Process.pid and @thread&.alive?
|
33
|
+
end
|
34
|
+
|
35
|
+
def start_thread_with_collector_loop(config = Config.instance)
|
36
|
+
@thread = Thread.new do
|
37
|
+
loop do
|
38
|
+
run_sidekiq_metrics_collection
|
39
|
+
multiplier = 1 - (rand / 4)
|
40
|
+
sleep config.report_interval_seconds * multiplier
|
41
|
+
end
|
42
|
+
rescue StandardError => e
|
43
|
+
logger.error("Sidekiq metrics collector thread terminated with error: #{e.message}")
|
44
|
+
logger.error(e.backtrace.join("\n")) if e.backtrace
|
45
|
+
ensure
|
46
|
+
if @pid == Process.pid && !@thread.nil?
|
47
|
+
logger.info("Restarting Sidekiq metrics collector thread")
|
48
|
+
sleep(5)
|
49
|
+
start_thread_with_collector_loop
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def run_sidekiq_metrics_collection
|
55
|
+
return unless sidekiq_available?
|
56
|
+
return if Config.instance.sidekiq_metrics_disabled?
|
57
|
+
|
58
|
+
begin
|
59
|
+
queues = ::Sidekiq::Queue.all
|
60
|
+
return if queues.empty?
|
61
|
+
|
62
|
+
queues.each do |queue|
|
63
|
+
collect_queue_metrics(queue)
|
64
|
+
end
|
65
|
+
rescue StandardError => e
|
66
|
+
logger.error("Error collecting Sidekiq metrics: #{e.message}")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def sidekiq_available?
|
73
|
+
defined?(::Sidekiq) && ::Sidekiq.respond_to?(:redis)
|
74
|
+
end
|
75
|
+
|
76
|
+
def collect_queue_metrics(queue)
|
77
|
+
queue_name = queue.name
|
78
|
+
latency_ms = (queue.latency * 1000).ceil
|
79
|
+
|
80
|
+
report_sidekiq_metric(queue_name, latency_ms)
|
81
|
+
end
|
82
|
+
|
83
|
+
def report_sidekiq_metric(queue_name, queue_time)
|
84
|
+
Reporter.new(queue_time, "sidekiq_queue_time", "worker", queue_name).report
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -9,29 +9,66 @@ module Neetodeploy
|
|
9
9
|
|
10
10
|
class << self
|
11
11
|
include NeetoDeploy::Logger
|
12
|
-
|
13
|
-
def
|
12
|
+
|
13
|
+
def setup_rails_middleware
|
14
14
|
Neetodeploy::Autoscale.setup_rails if defined? Rails
|
15
15
|
end
|
16
16
|
|
17
17
|
def setup_rails
|
18
|
-
require "neetodeploy/autoscale/
|
18
|
+
require "neetodeploy/autoscale/rails"
|
19
|
+
end
|
20
|
+
|
21
|
+
def setup_sidekiq_metrics
|
22
|
+
require "neetodeploy/autoscale/sidekiq"
|
23
|
+
|
24
|
+
::Sidekiq.configure_server do
|
25
|
+
Neetodeploy::Sidekiq::MetricsCollector.start
|
26
|
+
end
|
19
27
|
end
|
20
28
|
|
21
29
|
def enable_middleware?
|
22
|
-
ENV["
|
30
|
+
ENV["DISABLE_NEETO_DEPLOY_AUTOSCALE"] != "true" && in_rails_server?
|
23
31
|
end
|
24
32
|
|
25
|
-
def
|
33
|
+
def enable_sidekiq_metrics?
|
34
|
+
ENV["DISABLE_NEETO_DEPLOY_SIDEKIQ_METRICS"] != "true" && defined?(::Sidekiq) && Sidekiq.server?
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize_rails_middleware
|
26
38
|
if enable_middleware?
|
27
|
-
logger.info("Setting up Neetodeploy autoscale middleware")
|
28
|
-
|
39
|
+
logger.info("Setting up Neetodeploy rails autoscale middleware")
|
40
|
+
setup_rails_middleware
|
29
41
|
else
|
30
|
-
logger.info("
|
42
|
+
logger.info("Skipping NeetoDeploy rails autoscale middleware")
|
31
43
|
end
|
32
44
|
end
|
45
|
+
|
46
|
+
def initialize_sidekiq_metrics
|
47
|
+
if enable_sidekiq_metrics?
|
48
|
+
logger.info("Setting up Neetodeploy Sidekiq metrics middleware")
|
49
|
+
setup_sidekiq_metrics
|
50
|
+
else
|
51
|
+
logger.info("Skipping NeetoDeploy Sidekiq metrics middleware")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize_middlewares
|
56
|
+
return unless ENV["NEETODEPLOY_APP_NAME"].present?
|
57
|
+
|
58
|
+
initialize_rails_middleware
|
59
|
+
initialize_sidekiq_metrics
|
60
|
+
end
|
61
|
+
|
62
|
+
def in_rails_server?
|
63
|
+
# FIX ME: This is a gross way to detect if we're in a Rails server.
|
64
|
+
caller_keywords = %w[rails puma unicorn]
|
65
|
+
in_console = caller.any? { |call| call.include?("console_command.rb") || call.include?("runner_command.rb") }
|
66
|
+
is_rails = caller_keywords.any? { |key| File.basename($0).include?(key) }
|
67
|
+
!in_console && is_rails
|
68
|
+
end
|
69
|
+
|
33
70
|
end
|
34
71
|
end
|
35
72
|
end
|
36
73
|
|
37
|
-
Neetodeploy::Autoscale.
|
74
|
+
Neetodeploy::Autoscale.initialize_middlewares
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: neetodeploy-autoscale
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sreeram Venkitesh
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-09-23 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: For automatically scaling your Rails application based on network metrics
|
14
14
|
email:
|
@@ -25,12 +25,15 @@ files:
|
|
25
25
|
- lib/neetodeploy-autoscale.rb
|
26
26
|
- lib/neetodeploy/autoscale/config.rb
|
27
27
|
- lib/neetodeploy/autoscale/logger.rb
|
28
|
-
- lib/neetodeploy/autoscale/
|
29
|
-
- lib/neetodeploy/autoscale/
|
30
|
-
- lib/neetodeploy/autoscale/
|
31
|
-
- lib/neetodeploy/autoscale/
|
32
|
-
- lib/neetodeploy/autoscale/
|
28
|
+
- lib/neetodeploy/autoscale/rails.rb
|
29
|
+
- lib/neetodeploy/autoscale/rails/metrics.rb
|
30
|
+
- lib/neetodeploy/autoscale/rails/metrics_collector.rb
|
31
|
+
- lib/neetodeploy/autoscale/rails/metrics_store.rb
|
32
|
+
- lib/neetodeploy/autoscale/rails/middleware.rb
|
33
|
+
- lib/neetodeploy/autoscale/rails/railtie.rb
|
33
34
|
- lib/neetodeploy/autoscale/reporter.rb
|
35
|
+
- lib/neetodeploy/autoscale/sidekiq.rb
|
36
|
+
- lib/neetodeploy/autoscale/sidekiq/metrics_collector.rb
|
34
37
|
- lib/neetodeploy/autoscale/version.rb
|
35
38
|
homepage: https://neetodeploy.com
|
36
39
|
licenses: []
|
@@ -53,7 +56,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
56
|
- !ruby/object:Gem::Version
|
54
57
|
version: '0'
|
55
58
|
requirements: []
|
56
|
-
rubygems_version: 3.4.
|
59
|
+
rubygems_version: 3.4.1
|
57
60
|
signing_key:
|
58
61
|
specification_version: 4
|
59
62
|
summary: neetoDeploy autoscaler gem
|
@@ -1,26 +0,0 @@
|
|
1
|
-
require "neetodeploy/autoscale/config"
|
2
|
-
|
3
|
-
module Neetodeploy
|
4
|
-
class Metrics
|
5
|
-
def initialize(env, config = Config.instance)
|
6
|
-
@config = config
|
7
|
-
@request_start_header = env["HTTP_X_REQUEST_START"].to_i
|
8
|
-
@network_time = env["puma.request_body_wait"].to_i
|
9
|
-
end
|
10
|
-
|
11
|
-
def ignore?
|
12
|
-
@config.gem_disabled?
|
13
|
-
end
|
14
|
-
|
15
|
-
def queue_time
|
16
|
-
return if @request_start_header.zero?
|
17
|
-
|
18
|
-
time_now = Time.now.to_f * 1000
|
19
|
-
|
20
|
-
queue_time = (time_now - @request_start_header).round
|
21
|
-
queue_time -= @network_time
|
22
|
-
|
23
|
-
queue_time.positive? ? queue_time : nil
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "singleton"
|
4
|
-
require "neetodeploy/autoscale/metrics_store"
|
5
|
-
require "neetodeploy/autoscale/reporter"
|
6
|
-
require "neetodeploy/autoscale/logger"
|
7
|
-
|
8
|
-
module Neetodeploy
|
9
|
-
class MetricsCollector
|
10
|
-
include Singleton
|
11
|
-
include NeetoDeploy::Logger
|
12
|
-
|
13
|
-
def self.start
|
14
|
-
instance.start! unless instance.running?
|
15
|
-
end
|
16
|
-
|
17
|
-
def start!
|
18
|
-
logger.info("Starting background worker to collect metrics")
|
19
|
-
@pid = Process.pid
|
20
|
-
start_thread_with_collector_loop
|
21
|
-
end
|
22
|
-
|
23
|
-
def stop!
|
24
|
-
@thread&.terminate
|
25
|
-
@thread = nil
|
26
|
-
@pid = nil
|
27
|
-
end
|
28
|
-
|
29
|
-
def running?
|
30
|
-
@pid == Process.pid and @thread.alive?
|
31
|
-
end
|
32
|
-
|
33
|
-
def start_thread_with_collector_loop(config = Config.instance)
|
34
|
-
@thread = Thread.new do
|
35
|
-
metrics_store = MetricsStore.instance
|
36
|
-
loop do
|
37
|
-
run_metrics_collection(metrics_store)
|
38
|
-
multiplier = 1 - (rand / 4)
|
39
|
-
sleep config.report_interval_seconds * multiplier
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def run_metrics_collection(metrics_store)
|
45
|
-
data = metrics_store.flush
|
46
|
-
return if data.empty?
|
47
|
-
|
48
|
-
average_queue_time = data.sum / data.size
|
49
|
-
logger.info("Reporting average queue time of #{data.size} metrics: #{average_queue_time}")
|
50
|
-
Reporter.new(average_queue_time).report
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "singleton"
|
4
|
-
|
5
|
-
module Neetodeploy
|
6
|
-
class MetricsStore
|
7
|
-
include Singleton
|
8
|
-
|
9
|
-
attr_reader :metrics
|
10
|
-
|
11
|
-
def initialize
|
12
|
-
@metrics = []
|
13
|
-
end
|
14
|
-
|
15
|
-
def push(queue_time)
|
16
|
-
@metrics << queue_time
|
17
|
-
end
|
18
|
-
|
19
|
-
def flush
|
20
|
-
result = @metrics
|
21
|
-
@metrics = []
|
22
|
-
result
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "net/http"
|
4
|
-
require "time"
|
5
|
-
require "neetodeploy/autoscale/metrics"
|
6
|
-
require "neetodeploy/autoscale/metrics_store"
|
7
|
-
require "neetodeploy/autoscale/metrics_collector"
|
8
|
-
|
9
|
-
module Neetodeploy
|
10
|
-
class Middleware
|
11
|
-
def initialize(app)
|
12
|
-
@app = app
|
13
|
-
end
|
14
|
-
|
15
|
-
def call(env)
|
16
|
-
metrics = Metrics.new(env)
|
17
|
-
queue_time = metrics.queue_time unless metrics.ignore?
|
18
|
-
MetricsCollector.start
|
19
|
-
|
20
|
-
if queue_time
|
21
|
-
store = MetricsStore.instance
|
22
|
-
store.push queue_time
|
23
|
-
end
|
24
|
-
|
25
|
-
@app.call(env)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "neetodeploy/autoscale/middleware"
|
4
|
-
module Neetodeploy
|
5
|
-
class Railtie < Rails::Railtie
|
6
|
-
initializer "neetodeploy.Neetodeploy.middleware" do |app|
|
7
|
-
app.middleware.insert_before Rack::Runtime, Neetodeploy::Middleware
|
8
|
-
end
|
9
|
-
|
10
|
-
config.after_initialize do
|
11
|
-
MetricsCollector.start unless in_rails_console_or_runner?
|
12
|
-
end
|
13
|
-
|
14
|
-
def in_rails_console_or_runner?
|
15
|
-
# This is gross, but we can't find a more reliable way to detect if we're in a Rails console/runner.
|
16
|
-
caller.any? { |call| call.include?("console_command.rb") || call.include?("runner_command.rb") }
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|