neetodeploy-autoscale 2.1.5 → 2.1.6
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 +13 -18
- data/lib/neetodeploy/autoscale/rails/metrics.rb +3 -44
- data/lib/neetodeploy/autoscale/rails/metrics_collector.rb +55 -75
- data/lib/neetodeploy/autoscale/rails/metrics_store.rb +5 -50
- data/lib/neetodeploy/autoscale/rails/middleware.rb +11 -5
- data/lib/neetodeploy/autoscale/reporter.rb +24 -86
- data/lib/neetodeploy/autoscale/sidekiq/metrics_collector.rb +1 -1
- data/lib/neetodeploy/autoscale/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3b6d47e127492bf2a818f87ad72b9a57c70bb1c4d124b620a495a73d6a814779
|
|
4
|
+
data.tar.gz: 0d211f2a58c654f5e451dcf58c43cac205b0210855afbc4f43ef8db6cb55f66a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c6647e9faad55fb5e79b2321cb848ebb34d65ec5fae65ee99f0f7cfabf5b018caecb20a38811dd07d4b91ee0acb770ade98c5d46be674fe360d888a5082f989c
|
|
7
|
+
data.tar.gz: 1fd46a9ae0725de810b3109a5011ad7cebea3c851f14168773d8ce3a205cb22f1756ec0f88440badbd84f5f4f3c107b1d5f067494b6446cfda44adbad77f08c9
|
|
@@ -2,35 +2,30 @@ module Neetodeploy
|
|
|
2
2
|
class Config
|
|
3
3
|
include Singleton
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
DEFAULT_AUTH_TOKEN = "K0An3O3MSyEEMTCnRd1IHgGjdGQkzy"
|
|
8
|
-
DEFAULT_REPORT_INTERVAL = 10
|
|
9
|
-
|
|
10
|
-
attr_reader :app_name, :metrics_server_url, :metrics_server_batch_url,
|
|
11
|
-
:metrics_server_auth_token, :report_interval_seconds
|
|
5
|
+
attr_accessor :disable_auto_scale_gem, :disable_sidekiq_metrics, :app_name, :process_type,
|
|
6
|
+
:metrics_server_url, :metrics_server_auth_token, :report_interval_seconds, :use_puma_queue_size
|
|
12
7
|
|
|
13
8
|
def initialize
|
|
9
|
+
@disable_auto_scale_gem = ENV["DISABLE_NEETO_DEPLOY_AUTOSCALE"]
|
|
10
|
+
@disable_sidekiq_metrics = ENV["DISABLE_NEETO_DEPLOY_SIDEKIQ_METRICS"]
|
|
14
11
|
@app_name = ENV["NEETODEPLOY_APP_NAME"]
|
|
15
|
-
@
|
|
16
|
-
@
|
|
17
|
-
@metrics_server_auth_token =
|
|
18
|
-
@report_interval_seconds =
|
|
19
|
-
@
|
|
20
|
-
@sidekiq_metrics_disabled = ENV["DISABLE_NEETO_DEPLOY_SIDEKIQ_METRICS"] == "true"
|
|
21
|
-
@batch_processing_enabled = ENV["NEETODEPLOY_BATCH_PROCESSING_ENABLED"] == "true"
|
|
12
|
+
@process_type = ENV["NEETODEPLOY_PROCESS_TYPE"] || "worker"
|
|
13
|
+
@metrics_server_url = "http://nd-queue-time-exporter-web-deployment:3000/metrics"
|
|
14
|
+
@metrics_server_auth_token = "K0An3O3MSyEEMTCnRd1IHgGjdGQkzy"
|
|
15
|
+
@report_interval_seconds = 10
|
|
16
|
+
@use_puma_queue_size = ENV["NEETODEPLOY_USE_PUMA_QUEUE_SIZE"] == "true"
|
|
22
17
|
end
|
|
23
18
|
|
|
24
19
|
def gem_disabled?
|
|
25
|
-
|
|
20
|
+
disable_auto_scale_gem == "true"
|
|
26
21
|
end
|
|
27
22
|
|
|
28
23
|
def sidekiq_metrics_disabled?
|
|
29
|
-
|
|
24
|
+
disable_sidekiq_metrics == "true"
|
|
30
25
|
end
|
|
31
26
|
|
|
32
|
-
def
|
|
33
|
-
|
|
27
|
+
def use_puma_queue_size?
|
|
28
|
+
use_puma_queue_size == true
|
|
34
29
|
end
|
|
35
30
|
end
|
|
36
31
|
end
|
|
@@ -1,69 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "neetodeploy/autoscale/config"
|
|
4
|
-
require "neetodeploy/autoscale/logger"
|
|
5
4
|
|
|
6
5
|
module Neetodeploy
|
|
7
6
|
module Rails
|
|
8
7
|
class Metrics
|
|
9
8
|
def initialize(env, config = Config.instance)
|
|
10
9
|
@config = config
|
|
11
|
-
@
|
|
12
|
-
@request_start_header_raw = env["HTTP_X_REQUEST_START"]
|
|
13
|
-
@request_start_header = @request_start_header_raw.to_i
|
|
10
|
+
@request_start_header = env["HTTP_X_REQUEST_START"].to_i
|
|
14
11
|
@network_time = env["puma.request_body_wait"].to_i
|
|
15
|
-
|
|
16
|
-
# Debug: Log all HTTP headers to help diagnose (only for non-health-check requests)
|
|
17
|
-
if (@request_start_header_raw.nil? || @request_start_header_raw.empty?) && !health_check_request?(env)
|
|
18
|
-
# Get all HTTP_* headers (these are the request headers)
|
|
19
|
-
http_headers = env.keys.grep(/^HTTP_/)
|
|
20
|
-
|
|
21
|
-
if http_headers.any?
|
|
22
|
-
NeetoDeploy::Logger.logger.debug("All HTTP headers found: #{http_headers.sort.join(', ')}")
|
|
23
|
-
else
|
|
24
|
-
NeetoDeploy::Logger.logger.debug("No HTTP headers found in env. Available env keys: #{env.keys.grep(/^HTTP|^REQUEST|^SERVER/).sort.join(', ')}")
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# Also check for X-Request-Start with different casing
|
|
28
|
-
x_request_variants = env.select { |k, _| k.to_s.upcase.include?("REQUEST_START") || k.to_s.upcase.include?("X_REQUEST") }
|
|
29
|
-
if x_request_variants.any?
|
|
30
|
-
NeetoDeploy::Logger.logger.debug("Found X-Request-Start variants: #{x_request_variants.keys.join(', ')}")
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
12
|
end
|
|
34
13
|
|
|
35
14
|
def ignore?
|
|
36
|
-
@config.gem_disabled?
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def health_check_request?(env = @env)
|
|
40
|
-
# Ignore health check endpoints that don't go through Traefik
|
|
41
|
-
# These typically come from Kubernetes liveness/readiness probes
|
|
42
|
-
path = env["PATH_INFO"] || env["REQUEST_PATH"] || ""
|
|
43
|
-
path.match?(%r{/health_check|/health|/up|/ready|/live})
|
|
15
|
+
@config.gem_disabled?
|
|
44
16
|
end
|
|
45
17
|
|
|
46
18
|
def queue_time
|
|
47
|
-
|
|
48
|
-
if @request_start_header_raw.nil? || @request_start_header_raw.empty?
|
|
49
|
-
NeetoDeploy::Logger.logger.debug("X-Request-Start header missing or empty")
|
|
50
|
-
return nil
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
return nil if @request_start_header.zero?
|
|
19
|
+
return if @request_start_header.zero?
|
|
54
20
|
|
|
55
21
|
time_now = Time.now.to_f * 1000
|
|
56
22
|
|
|
57
23
|
queue_time = (time_now - @request_start_header).round
|
|
58
24
|
queue_time -= @network_time
|
|
59
25
|
|
|
60
|
-
# Log both values for debugging
|
|
61
|
-
NeetoDeploy::Logger.logger.debug(
|
|
62
|
-
"Queue time calculation: X-Request-Start=#{@request_start_header_raw} (#{@request_start_header}ms), " \
|
|
63
|
-
"puma.request_body_wait=#{@network_time}ms, time_now=#{time_now.round}ms, " \
|
|
64
|
-
"calculated_queue_time=#{queue_time}ms"
|
|
65
|
-
)
|
|
66
|
-
|
|
67
26
|
queue_time.positive? ? queue_time : nil
|
|
68
27
|
end
|
|
69
28
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "singleton"
|
|
4
|
+
require "json"
|
|
4
5
|
require "neetodeploy/autoscale/reporter"
|
|
5
6
|
require "neetodeploy/autoscale/logger"
|
|
6
7
|
require "neetodeploy/autoscale/config"
|
|
@@ -12,17 +13,16 @@ module Neetodeploy
|
|
|
12
13
|
include Singleton
|
|
13
14
|
include NeetoDeploy::Logger
|
|
14
15
|
|
|
15
|
-
PERCENTILES = { p90: 0.90, p95: 0.95, p99: 0.99 }.freeze
|
|
16
|
-
RESTART_DELAY = 5
|
|
17
|
-
|
|
18
16
|
def self.start
|
|
19
17
|
instance.start! unless instance.running?
|
|
20
18
|
end
|
|
21
19
|
|
|
22
20
|
def start!
|
|
23
|
-
|
|
21
|
+
config = Config.instance
|
|
22
|
+
mode = config.use_puma_queue_size? ? "Puma queue size" : "response time"
|
|
23
|
+
logger.info("Starting background worker to collect #{mode} metrics")
|
|
24
24
|
@pid = Process.pid
|
|
25
|
-
|
|
25
|
+
start_thread_with_collector_loop
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def stop!
|
|
@@ -32,28 +32,30 @@ module Neetodeploy
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def running?
|
|
35
|
-
@pid == Process.pid
|
|
35
|
+
@pid == Process.pid and @thread&.alive?
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def start_collector_thread(config = Config.instance)
|
|
38
|
+
def start_thread_with_collector_loop(config = Config.instance)
|
|
41
39
|
@thread = Thread.new do
|
|
40
|
+
metrics_store = MetricsStore.instance unless config.use_puma_queue_size?
|
|
42
41
|
loop do
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
handle_collection_error(e, config)
|
|
42
|
+
if config.use_puma_queue_size?
|
|
43
|
+
run_puma_metrics_collection(config)
|
|
44
|
+
else
|
|
45
|
+
run_queue_time_collection(metrics_store, config)
|
|
48
46
|
end
|
|
47
|
+
multiplier = 1 - (rand / 4)
|
|
48
|
+
sleep config.report_interval_seconds * multiplier
|
|
49
|
+
end
|
|
50
|
+
rescue StandardError => e
|
|
51
|
+
logger.error("Rails metrics collector thread terminated with error: #{e.message}")
|
|
52
|
+
logger.error(e.backtrace.join("\n")) if e.backtrace
|
|
53
|
+
ensure
|
|
54
|
+
if @pid == Process.pid && !@thread.nil?
|
|
55
|
+
logger.info("Restarting Rails metrics collector thread")
|
|
56
|
+
sleep(5)
|
|
57
|
+
start_thread_with_collector_loop
|
|
49
58
|
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def collect_and_report_loop(metrics_store, config)
|
|
54
|
-
loop do
|
|
55
|
-
run_queue_time_collection(metrics_store, config)
|
|
56
|
-
sleep(config.report_interval_seconds)
|
|
57
59
|
end
|
|
58
60
|
end
|
|
59
61
|
|
|
@@ -63,71 +65,49 @@ module Neetodeploy
|
|
|
63
65
|
data = metrics_store.flush
|
|
64
66
|
return if data.empty?
|
|
65
67
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
else
|
|
69
|
-
report_average_metric(data, config)
|
|
70
|
-
end
|
|
68
|
+
average_queue_time = data.sum / data.size
|
|
69
|
+
Reporter.new(average_queue_time, "queue_time", "web").report
|
|
71
70
|
end
|
|
72
71
|
|
|
73
|
-
def
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
# Calculate percentiles
|
|
78
|
-
p90 = percentile_value(sorted_data, size, 0.90)
|
|
79
|
-
p95 = percentile_value(sorted_data, size, 0.95)
|
|
80
|
-
p99 = percentile_value(sorted_data, size, 0.99)
|
|
81
|
-
avg = data.sum / data.size
|
|
82
|
-
|
|
83
|
-
min_val = sorted_data.first
|
|
84
|
-
max_val = sorted_data.last
|
|
85
|
-
logger.debug("Calculated metrics from #{size} samples: min=#{min_val}, max=#{max_val}, avg=#{avg}, p90=#{p90}, p95=#{p95}, p99=#{p99}")
|
|
72
|
+
def run_puma_metrics_collection(config)
|
|
73
|
+
return unless puma_available?
|
|
74
|
+
return if config.gem_disabled?
|
|
86
75
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
logger.debug("Sample values: first 5=#{sorted_data[0..4].join(', ')}, last 5=#{sorted_data[-5..-1].join(', ')}")
|
|
91
|
-
end
|
|
76
|
+
begin
|
|
77
|
+
queue_size = get_puma_queue_size
|
|
78
|
+
return if queue_size.nil?
|
|
92
79
|
|
|
93
|
-
|
|
94
|
-
|
|
80
|
+
Reporter.new(queue_size, "puma_queue_size", "web").report
|
|
81
|
+
rescue StandardError => e
|
|
82
|
+
logger.error("Error collecting Puma queue size metrics: #{e.message}")
|
|
95
83
|
end
|
|
96
|
-
|
|
97
|
-
metrics = [
|
|
98
|
-
{ metric_name: "queue_time_p90", metric_value: p90 },
|
|
99
|
-
{ metric_name: "queue_time_p95", metric_value: p95 },
|
|
100
|
-
{ metric_name: "queue_time_p99", metric_value: p99 },
|
|
101
|
-
{ metric_name: "queue_time_max", metric_value: max_val },
|
|
102
|
-
{ metric_name: "queue_time", metric_value: avg }
|
|
103
|
-
]
|
|
104
|
-
|
|
105
|
-
Reporter.report_batch(metrics, "web", nil, config)
|
|
106
84
|
end
|
|
107
85
|
|
|
108
|
-
|
|
109
|
-
average_queue_time = data.sum.fdiv(data.size).round
|
|
110
|
-
Reporter.new(average_queue_time, "queue_time", "web", nil, config).report
|
|
111
|
-
end
|
|
86
|
+
private
|
|
112
87
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
index = [(size * percentile).ceil - 1, 0].max
|
|
117
|
-
# Clamp index to valid range
|
|
118
|
-
index = [index, size - 1].min
|
|
119
|
-
sorted_data[index]
|
|
120
|
-
end
|
|
88
|
+
def puma_available?
|
|
89
|
+
defined?(::Puma) && ::Puma.respond_to?(:stats)
|
|
90
|
+
end
|
|
121
91
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
92
|
+
def get_puma_queue_size
|
|
93
|
+
stats_json = ::Puma.stats
|
|
94
|
+
return nil if stats_json.nil? || stats_json.empty?
|
|
125
95
|
|
|
126
|
-
|
|
127
|
-
logger.info("Restarting Rails metrics collector thread") if should_restart
|
|
96
|
+
stats = JSON.parse(stats_json)
|
|
128
97
|
|
|
129
|
-
|
|
130
|
-
|
|
98
|
+
# For clustered mode (multiple workers)
|
|
99
|
+
if stats["worker_status"]
|
|
100
|
+
# Sum backlog from all workers
|
|
101
|
+
stats["worker_status"].sum do |worker|
|
|
102
|
+
worker.dig("last_status", "backlog") || 0
|
|
103
|
+
end
|
|
104
|
+
# For single mode
|
|
105
|
+
elsif stats["backlog"]
|
|
106
|
+
stats["backlog"]
|
|
107
|
+
else
|
|
108
|
+
nil
|
|
109
|
+
end
|
|
110
|
+
end
|
|
131
111
|
end
|
|
132
112
|
end
|
|
133
113
|
end
|
|
@@ -1,71 +1,26 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "singleton"
|
|
4
|
-
require "neetodeploy/autoscale/logger"
|
|
5
4
|
|
|
6
5
|
module Neetodeploy
|
|
7
6
|
module Rails
|
|
8
7
|
class MetricsStore
|
|
9
8
|
include Singleton
|
|
10
9
|
|
|
11
|
-
# Use sliding window: keep last 2 minutes of data (120 seconds)
|
|
12
|
-
# At 2s reporting interval, this gives us ~60 samples per window
|
|
13
|
-
# This ensures percentiles work correctly even with low traffic
|
|
14
|
-
WINDOW_SIZE_SECONDS = 120
|
|
15
|
-
MAX_SAMPLES = 1000 # Safety limit to prevent memory bloat
|
|
16
|
-
|
|
17
10
|
attr_reader :metrics
|
|
18
11
|
|
|
19
12
|
def initialize
|
|
20
|
-
@metrics = []
|
|
21
|
-
@mutex = Mutex.new
|
|
13
|
+
@metrics = []
|
|
22
14
|
end
|
|
23
15
|
|
|
24
16
|
def push(queue_time)
|
|
25
|
-
@
|
|
26
|
-
now = Time.now.to_f
|
|
27
|
-
@metrics << { time: now, value: queue_time }
|
|
28
|
-
|
|
29
|
-
# Remove old data outside window
|
|
30
|
-
cutoff = now - WINDOW_SIZE_SECONDS
|
|
31
|
-
@metrics.reject! { |m| m[:time] < cutoff }
|
|
32
|
-
|
|
33
|
-
# Safety limit: keep only most recent samples
|
|
34
|
-
if @metrics.size > MAX_SAMPLES
|
|
35
|
-
@metrics = @metrics.last(MAX_SAMPLES)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Log high queue times to help debug
|
|
39
|
-
if queue_time > 500
|
|
40
|
-
NeetoDeploy::Logger.logger.debug("MetricsStore: Pushed high queue_time=#{queue_time}ms (total in window: #{@metrics.size})")
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Get recent samples from the sliding window (last N seconds)
|
|
46
|
-
def get_recent(seconds = WINDOW_SIZE_SECONDS)
|
|
47
|
-
@mutex.synchronize do
|
|
48
|
-
cutoff = Time.now.to_f - seconds
|
|
49
|
-
@metrics.select { |m| m[:time] >= cutoff }.map { |m| m[:value] }
|
|
50
|
-
end
|
|
17
|
+
@metrics << queue_time
|
|
51
18
|
end
|
|
52
19
|
|
|
53
|
-
# Flush: return all values in window, but DON'T clear (sliding window)
|
|
54
|
-
# This allows high values to persist across multiple reporting cycles
|
|
55
20
|
def flush
|
|
56
|
-
@
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
@metrics.reject! { |m| m[:time] < cutoff }
|
|
60
|
-
|
|
61
|
-
result = @metrics.map { |m| m[:value] }
|
|
62
|
-
size = result.size
|
|
63
|
-
max_val = result.max if result.any?
|
|
64
|
-
NeetoDeploy::Logger.logger.debug("MetricsStore: Reporting from sliding window: #{size} values, max=#{max_val}ms") if result.any?
|
|
65
|
-
|
|
66
|
-
# Return values but keep them in the window for next cycle
|
|
67
|
-
result
|
|
68
|
-
end
|
|
21
|
+
result = @metrics
|
|
22
|
+
@metrics = []
|
|
23
|
+
result
|
|
69
24
|
end
|
|
70
25
|
end
|
|
71
26
|
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "neetodeploy/autoscale/rails/metrics"
|
|
4
4
|
require "neetodeploy/autoscale/rails/metrics_store"
|
|
5
5
|
require "neetodeploy/autoscale/rails/metrics_collector"
|
|
6
|
+
require "neetodeploy/autoscale/config"
|
|
6
7
|
|
|
7
8
|
module Neetodeploy
|
|
8
9
|
module Rails
|
|
@@ -12,13 +13,18 @@ module Neetodeploy
|
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def call(env)
|
|
15
|
-
|
|
16
|
-
queue_time = metrics.queue_time unless metrics.ignore?
|
|
16
|
+
config = Config.instance
|
|
17
17
|
MetricsCollector.start
|
|
18
18
|
|
|
19
|
-
if
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
# Only collect queue time per request if using the old response time method
|
|
20
|
+
unless config.use_puma_queue_size?
|
|
21
|
+
metrics = Metrics.new(env)
|
|
22
|
+
queue_time = metrics.queue_time unless metrics.ignore?
|
|
23
|
+
|
|
24
|
+
if queue_time
|
|
25
|
+
store = MetricsStore.instance
|
|
26
|
+
store.push queue_time
|
|
27
|
+
end
|
|
22
28
|
end
|
|
23
29
|
|
|
24
30
|
@app.call(env)
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require "net/http"
|
|
4
4
|
require "time"
|
|
5
|
-
require "json"
|
|
6
5
|
require "neetodeploy/autoscale/config"
|
|
7
6
|
require "neetodeploy/autoscale/logger"
|
|
8
7
|
|
|
@@ -19,100 +18,39 @@ module Neetodeploy
|
|
|
19
18
|
end
|
|
20
19
|
|
|
21
20
|
def report
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def self.report_batch(metrics, process_type, queue_name = nil, config = Config.instance)
|
|
28
|
-
return if metrics.empty?
|
|
21
|
+
params = common_params
|
|
22
|
+
params[:queue_name] = @queue_name if @queue_name
|
|
23
|
+
url = build_url(params)
|
|
24
|
+
logger.info("Reporting #{@metric_name} for #{@process_type} dyno: #{@metric_value}")
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
url = config.metrics_server_batch_url
|
|
32
|
-
|
|
33
|
-
NeetoDeploy::Logger.logger.info("Batch reporting #{metrics.size} metrics for #{process_type}")
|
|
34
|
-
post_batch_request(url, payload, config)
|
|
26
|
+
post_request(url)
|
|
35
27
|
end
|
|
36
28
|
|
|
37
29
|
private
|
|
38
30
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def build_url(params)
|
|
50
|
-
url = URI.parse(@config.metrics_server_url)
|
|
51
|
-
url.query = URI.encode_www_form(params)
|
|
52
|
-
url
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def post_request(url)
|
|
56
|
-
http_request(url, self.class.build_post_request(url, @config.metrics_server_auth_token))
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def self.build_batch_payload(metrics, process_type, queue_name, config)
|
|
60
|
-
{
|
|
61
|
-
app_name: config.app_name,
|
|
62
|
-
process_type: process_type,
|
|
63
|
-
queue_name: queue_name,
|
|
64
|
-
metrics: metrics.map { |m| { metric_name: m[:metric_name], metric_value: m[:metric_value].to_i } }
|
|
65
|
-
}.compact
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def self.post_batch_request(url, payload, config)
|
|
69
|
-
uri = URI.parse(url)
|
|
70
|
-
request = build_post_request(uri, config.metrics_server_auth_token)
|
|
71
|
-
request.body = JSON.generate(payload)
|
|
72
|
-
request["Content-Type"] = "application/json"
|
|
73
|
-
|
|
74
|
-
http_request(uri, request)
|
|
75
|
-
rescue StandardError => e
|
|
76
|
-
NeetoDeploy::Logger.logger.error("Error batch reporting metrics: #{e.message}")
|
|
77
|
-
raise
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def self.build_post_request(uri, auth_token)
|
|
81
|
-
post = Net::HTTP::Post.new(uri)
|
|
82
|
-
post["AuthToken"] = auth_token
|
|
83
|
-
post
|
|
84
|
-
end
|
|
31
|
+
def common_params
|
|
32
|
+
{
|
|
33
|
+
app_name: @config.app_name,
|
|
34
|
+
queue_time: @metric_value, # Keep queue_time parameter name for backward compatibility with metrics server
|
|
35
|
+
metric_name: @metric_name,
|
|
36
|
+
process_type: @process_type
|
|
37
|
+
}
|
|
38
|
+
end
|
|
85
39
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
"process_type=#{encode_param(payload[:process_type])}"
|
|
90
|
-
]
|
|
91
|
-
|
|
92
|
-
form_parts << "queue_name=#{encode_param(payload[:queue_name])}" if payload[:queue_name]
|
|
93
|
-
|
|
94
|
-
if payload[:metrics].is_a?(Array)
|
|
95
|
-
payload[:metrics].each do |metric|
|
|
96
|
-
form_parts << "metrics[][metric_name]=#{encode_param(metric[:metric_name])}"
|
|
97
|
-
form_parts << "metrics[][metric_value]=#{encode_param(metric[:metric_value])}"
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
form_parts.join("&")
|
|
102
|
-
end
|
|
40
|
+
def post_request(url)
|
|
41
|
+
post = Net::HTTP::Post.new(url)
|
|
42
|
+
post["AuthToken"] = @config.metrics_server_auth_token
|
|
103
43
|
|
|
104
|
-
|
|
105
|
-
|
|
44
|
+
Net::HTTP.start(url.host, url.port, use_ssl: false) do |http|
|
|
45
|
+
http.request(post)
|
|
106
46
|
end
|
|
47
|
+
end
|
|
107
48
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
end
|
|
112
|
-
end
|
|
49
|
+
def build_url(params = {})
|
|
50
|
+
exporter_url = URI.parse(@config.metrics_server_url)
|
|
51
|
+
exporter_url.query = URI.encode_www_form(params)
|
|
113
52
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
end
|
|
53
|
+
exporter_url
|
|
54
|
+
end
|
|
117
55
|
end
|
|
118
56
|
end
|
|
@@ -81,7 +81,7 @@ module Neetodeploy
|
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
def report_sidekiq_metric(queue_name, queue_time)
|
|
84
|
-
Reporter.new(queue_time, "sidekiq_queue_time",
|
|
84
|
+
Reporter.new(queue_time, "sidekiq_queue_time", Config.instance.process_type, queue_name).report
|
|
85
85
|
end
|
|
86
86
|
end
|
|
87
87
|
end
|
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.1.
|
|
4
|
+
version: 2.1.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sreeram Venkitesh
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-02-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: For automatically scaling your Rails application based on network metrics
|
|
14
14
|
email:
|
|
@@ -56,7 +56,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
56
56
|
- !ruby/object:Gem::Version
|
|
57
57
|
version: '0'
|
|
58
58
|
requirements: []
|
|
59
|
-
rubygems_version: 3.5.
|
|
59
|
+
rubygems_version: 3.5.22
|
|
60
60
|
signing_key:
|
|
61
61
|
specification_version: 4
|
|
62
62
|
summary: neetoDeploy autoscaler gem
|