rails-autoscale-core 1.3.0 → 1.4.0
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/Gemfile.lock +1 -1
- data/judoscale-ruby.gemspec +2 -2
- data/lib/judoscale/adapter_api.rb +9 -2
- data/lib/judoscale/config.rb +41 -18
- data/lib/judoscale/job_metrics_collector.rb +1 -2
- data/lib/judoscale/report.rb +1 -1
- data/lib/judoscale/reporter.rb +1 -1
- data/lib/judoscale/request_metrics.rb +16 -4
- data/lib/judoscale/version.rb +1 -1
- data/lib/judoscale/web_metrics_collector.rb +3 -1
- data/rails-autoscale-core.gemspec +2 -2
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9577515e0476c286fa4733675f8814cfbdbbff2f1cfa8260ada7a7d58ad1e6d2
|
4
|
+
data.tar.gz: dbefa4da91b6369b437404c884b1720e4789621b0ed0fc1a3eb6d09f32fef955
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a8338c11578ac27afd667a42b5cee2469ce7011007fefed9573dad3617d60f2b79c6d4c7b6347a38ba9ca739bda122647e105dd1b4b31f47127cdb06e64a5a7a
|
7
|
+
data.tar.gz: e05183812d63c61837229b76ce119df860316e2dc44d5817720c71b778852e65ab0db3e9f28a21b0f33ac6c40eae64a08e9e1de8803c894e504581e67973a320
|
data/Gemfile.lock
CHANGED
data/judoscale-ruby.gemspec
CHANGED
@@ -5,8 +5,8 @@ require "judoscale/version"
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "judoscale-ruby"
|
7
7
|
spec.version = Judoscale::VERSION
|
8
|
-
spec.authors = ["Adam McCrea", "Carlos Antonio da Silva"]
|
9
|
-
spec.email = ["
|
8
|
+
spec.authors = ["Adam McCrea", "Carlos Antonio da Silva", "Jon Sullivan"]
|
9
|
+
spec.email = ["hello@judoscale.com"]
|
10
10
|
|
11
11
|
spec.summary = "This gem works with the Judoscale Heroku add-on to automatically scale your web and worker dynos."
|
12
12
|
spec.homepage = "https://judoscale.com"
|
@@ -10,6 +10,13 @@ module Judoscale
|
|
10
10
|
include Logger
|
11
11
|
|
12
12
|
SUCCESS = "success"
|
13
|
+
TRANSIENT_ERRORS = [
|
14
|
+
Errno::ECONNREFUSED,
|
15
|
+
Errno::ECONNRESET,
|
16
|
+
Net::OpenTimeout,
|
17
|
+
Net::ReadTimeout,
|
18
|
+
OpenSSL::SSL::SSLError
|
19
|
+
]
|
13
20
|
|
14
21
|
def initialize(config)
|
15
22
|
@config = config
|
@@ -43,14 +50,14 @@ module Judoscale
|
|
43
50
|
when 200...300 then SuccessResponse.new(response.body)
|
44
51
|
else FailureResponse.new([response.code, response.message].join(" - "))
|
45
52
|
end
|
46
|
-
rescue
|
53
|
+
rescue *TRANSIENT_ERRORS => ex
|
47
54
|
if attempts < 3
|
48
55
|
# TCP timeouts happen sometimes, but they can usually be successfully retried in a moment
|
49
56
|
sleep 0.01
|
50
57
|
attempts += 1
|
51
58
|
retry
|
52
59
|
else
|
53
|
-
FailureResponse.new("
|
60
|
+
FailureResponse.new("Could not connect to #{uri.host}: #{ex.inspect}")
|
54
61
|
end
|
55
62
|
end
|
56
63
|
|
data/lib/judoscale/config.rb
CHANGED
@@ -5,16 +5,35 @@ require "logger"
|
|
5
5
|
|
6
6
|
module Judoscale
|
7
7
|
class Config
|
8
|
-
class
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
@
|
8
|
+
class RuntimeContainer
|
9
|
+
# E.g.:
|
10
|
+
# (Heroku) => "worker_fast", "3"
|
11
|
+
# (Render) => "srv-cfa1es5a49987h4vcvfg", "5497f74465-m5wwr", "web" (or "worker", "pserv", "cron", "static")
|
12
|
+
def initialize(service_name = nil, instance = nil, service_type = nil)
|
13
|
+
@service_name = service_name
|
14
|
+
@instance = instance
|
15
|
+
@service_type = service_type
|
14
16
|
end
|
15
17
|
|
16
18
|
def to_s
|
17
|
-
|
19
|
+
# heroku: 'worker_fast.5'
|
20
|
+
# render: 'srv-cfa1es5a49987h4vcvfg.5497f74465-m5wwr'
|
21
|
+
"#{@service_name}.#{@instance}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def web?
|
25
|
+
# NOTE: Heroku isolates 'web' as the required _name_ for its web process
|
26
|
+
# type, Render exposes the actual service type more explicitly
|
27
|
+
@service_name == "web" || @service_type == "web"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Since Heroku exposes ordinal dyno 'numbers', we can tell if the current
|
31
|
+
# instance is redundant (and thus skip collecting some metrics sometimes)
|
32
|
+
# We don't have a means of determining that on Render though — so every
|
33
|
+
# instance must be considered non-redundant
|
34
|
+
def redundant_instance?
|
35
|
+
instance_is_number = Integer(@instance, exception: false)
|
36
|
+
instance_is_number && instance_is_number != 1
|
18
37
|
end
|
19
38
|
end
|
20
39
|
|
@@ -66,28 +85,36 @@ module Judoscale
|
|
66
85
|
end
|
67
86
|
end
|
68
87
|
|
69
|
-
attr_accessor :api_base_url, :report_interval_seconds,
|
70
|
-
|
88
|
+
attr_accessor :api_base_url, :report_interval_seconds,
|
89
|
+
:max_request_size_bytes, :logger, :log_tag, :current_runtime_container
|
90
|
+
attr_reader :log_level
|
71
91
|
|
72
92
|
def initialize
|
73
93
|
reset
|
74
94
|
end
|
75
95
|
|
76
96
|
def reset
|
77
|
-
# Allow the API URL to be configured - needed for testing.
|
78
97
|
@api_base_url = ENV["JUDOSCALE_URL"] || ENV["RAILS_AUTOSCALE_URL"]
|
79
98
|
@log_tag = "Judoscale"
|
80
|
-
self.dyno = ENV["DYNO"]
|
81
99
|
@max_request_size_bytes = 100_000 # ignore request payloads over 100k since they skew the queue times
|
82
100
|
@report_interval_seconds = 10
|
101
|
+
|
83
102
|
self.log_level = ENV["JUDOSCALE_LOG_LEVEL"] || ENV["RAILS_AUTOSCALE_LOG_LEVEL"]
|
84
103
|
@logger = ::Logger.new($stdout)
|
85
104
|
|
86
105
|
self.class.adapter_configs.each(&:reset)
|
87
|
-
end
|
88
106
|
|
89
|
-
|
90
|
-
|
107
|
+
if ENV["RENDER_INSTANCE_ID"]
|
108
|
+
instance = ENV["RENDER_INSTANCE_ID"].delete_prefix(ENV["RENDER_SERVICE_ID"]).delete_prefix("-")
|
109
|
+
@current_runtime_container = RuntimeContainer.new ENV["RENDER_SERVICE_ID"], instance, ENV["RENDER_SERVICE_TYPE"]
|
110
|
+
@api_base_url ||= "https://adapter.judoscale.com/api/#{ENV["RENDER_SERVICE_ID"]}"
|
111
|
+
elsif ENV["DYNO"]
|
112
|
+
service_name, instance = ENV["DYNO"].split "."
|
113
|
+
@current_runtime_container = RuntimeContainer.new service_name, instance
|
114
|
+
else
|
115
|
+
# unsupported platform? Don't want to leave @current_runtime_container nil though
|
116
|
+
@current_runtime_container = RuntimeContainer.new
|
117
|
+
end
|
91
118
|
end
|
92
119
|
|
93
120
|
def log_level=(new_level)
|
@@ -105,10 +132,6 @@ module Judoscale
|
|
105
132
|
}.merge!(adapter_configs_json)
|
106
133
|
end
|
107
134
|
|
108
|
-
def to_s
|
109
|
-
"#{@dyno}##{Process.pid}"
|
110
|
-
end
|
111
|
-
|
112
135
|
def ignore_large_requests?
|
113
136
|
@max_request_size_bytes
|
114
137
|
end
|
@@ -8,9 +8,8 @@ module Judoscale
|
|
8
8
|
class JobMetricsCollector < MetricsCollector
|
9
9
|
include Judoscale::Logger
|
10
10
|
|
11
|
-
# It's redundant to report these metrics from every dyno, so only report from the first one.
|
12
11
|
def self.collect?(config)
|
13
|
-
config.
|
12
|
+
!config.current_runtime_container.redundant_instance? && adapter_config.enabled
|
14
13
|
end
|
15
14
|
|
16
15
|
def self.adapter_name
|
data/lib/judoscale/report.rb
CHANGED
data/lib/judoscale/reporter.rb
CHANGED
@@ -31,7 +31,7 @@ module Judoscale
|
|
31
31
|
metrics_collectors_classes.compact!
|
32
32
|
|
33
33
|
if metrics_collectors_classes.empty?
|
34
|
-
logger.info "Reporter not started: no metrics need to be collected
|
34
|
+
logger.info "Reporter not started: no metrics need to be collected in this process"
|
35
35
|
return
|
36
36
|
end
|
37
37
|
|
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
module Judoscale
|
4
4
|
class RequestMetrics
|
5
|
+
MILLISECONDS_CUTOFF = Time.new(2000, 1, 1).to_i * 1000
|
6
|
+
MICROSECONDS_CUTOFF = MILLISECONDS_CUTOFF * 1000
|
7
|
+
NANOSECONDS_CUTOFF = MICROSECONDS_CUTOFF * 1000
|
8
|
+
|
5
9
|
attr_reader :request_id, :size, :network_time
|
6
10
|
|
7
11
|
def initialize(env, config = Config.instance)
|
@@ -20,15 +24,23 @@ module Judoscale
|
|
20
24
|
if @request_start_header
|
21
25
|
# There are several variants of this header. We handle these:
|
22
26
|
# - whole milliseconds (Heroku)
|
27
|
+
# - whole microseconds (???)
|
23
28
|
# - whole nanoseconds (Render)
|
24
29
|
# - fractional seconds (NGINX)
|
25
30
|
# - preceeding "t=" (NGINX)
|
26
31
|
value = @request_start_header.gsub(/[^0-9.]/, "").to_f
|
27
32
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
33
|
+
# `value` could be seconds, milliseconds, microseconds or nanoseconds.
|
34
|
+
# We use some arbitrary cutoffs to determine which one it is.
|
35
|
+
|
36
|
+
if value > NANOSECONDS_CUTOFF
|
37
|
+
Time.at(value / 1_000_000_000.0)
|
38
|
+
elsif value > MICROSECONDS_CUTOFF
|
39
|
+
Time.at(value / 1_000_000.0)
|
40
|
+
elsif value > MILLISECONDS_CUTOFF
|
41
|
+
Time.at(value / 1000.0)
|
42
|
+
else
|
43
|
+
Time.at(value)
|
32
44
|
end
|
33
45
|
end
|
34
46
|
end
|
data/lib/judoscale/version.rb
CHANGED
@@ -5,8 +5,10 @@ require "judoscale/metrics_store"
|
|
5
5
|
|
6
6
|
module Judoscale
|
7
7
|
class WebMetricsCollector < MetricsCollector
|
8
|
+
# NOTE: We collect metrics on all running web processes since they
|
9
|
+
# all receive and handle requests independently
|
8
10
|
def self.collect?(config)
|
9
|
-
config.
|
11
|
+
config.current_runtime_container.web?
|
10
12
|
end
|
11
13
|
|
12
14
|
def collect
|
@@ -5,8 +5,8 @@ require "judoscale/version"
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "rails-autoscale-core"
|
7
7
|
spec.version = Judoscale::VERSION
|
8
|
-
spec.authors = ["Adam McCrea", "Carlos Antonio da Silva"]
|
9
|
-
spec.email = ["
|
8
|
+
spec.authors = ["Adam McCrea", "Carlos Antonio da Silva", "Jon Sullivan"]
|
9
|
+
spec.email = ["hello@judoscale.com"]
|
10
10
|
|
11
11
|
spec.summary = "This gem works with the Judoscale Heroku add-on to automatically scale your web and worker dynos."
|
12
12
|
spec.homepage = "https://judoscale.com"
|
metadata
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-autoscale-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam McCrea
|
8
8
|
- Carlos Antonio da Silva
|
9
|
+
- Jon Sullivan
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date: 2023-
|
13
|
+
date: 2023-04-21 00:00:00.000000000 Z
|
13
14
|
dependencies: []
|
14
15
|
description:
|
15
16
|
email:
|
16
|
-
-
|
17
|
+
- hello@judoscale.com
|
17
18
|
executables: []
|
18
19
|
extensions: []
|
19
20
|
extra_rdoc_files: []
|