judoscale-ruby 1.13.3 → 1.13.4
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/judoscale/config.rb +5 -38
- data/lib/judoscale/job_metrics_collector.rb +1 -1
- data/lib/judoscale/platform.rb +116 -0
- data/lib/judoscale/report.rb +1 -1
- data/lib/judoscale/reporter.rb +5 -0
- data/lib/judoscale/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a9bf6350ab170b86f70461084c4e22bc462826e58c83811ba00068050f6677d8
|
|
4
|
+
data.tar.gz: 0ddbfb24c27cce98a0ce7cc4e24af1a0df7733e92a06010023643dad2b25bed9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 14f1dee46bbf8f676500f6c9674aabb876e69e3dd18305eb420813a8ee0b72d86f8e084ac788d9b38879c46a972ccc16a8207057052d7068e748ab0899213d4f
|
|
7
|
+
data.tar.gz: 770ccd3b9725fea1dcff4dfe7d2bbacdda6ec843252dbc42f3e8c30863889550bcc0040781310223ef58d85f757bff84b7d2d14baa9ca7ef70d8c58bb85b0262
|
data/lib/judoscale/config.rb
CHANGED
|
@@ -2,21 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
require "singleton"
|
|
4
4
|
require "logger"
|
|
5
|
+
require "judoscale/platform"
|
|
5
6
|
|
|
6
7
|
module Judoscale
|
|
7
8
|
class Config
|
|
8
|
-
class RuntimeContainer < String
|
|
9
|
-
# Job metrics are collected from a single container per process type when we
|
|
10
|
-
# can identify the ordinal instance (Heroku "web.2", Scalingo "web-2").
|
|
11
|
-
# Opaque IDs (Render, ECS, Railway, etc.) are always non-redundant.
|
|
12
|
-
ORDINAL_CONTAINER = /\A[a-z_]+[.-](\d{1,3})\z/
|
|
13
|
-
|
|
14
|
-
def redundant_instance?
|
|
15
|
-
match = match(ORDINAL_CONTAINER)
|
|
16
|
-
match ? match[1].to_i > 1 : false
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
9
|
class JobAdapterConfig
|
|
21
10
|
UUID_REGEXP = /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/
|
|
22
11
|
DEFAULT_QUEUE_FILTER = ->(queue_name) { !UUID_REGEXP.match?(queue_name) }
|
|
@@ -90,7 +79,7 @@ module Judoscale
|
|
|
90
79
|
end
|
|
91
80
|
|
|
92
81
|
attr_accessor :api_base_url, :report_interval_seconds,
|
|
93
|
-
:max_request_size_bytes, :logger, :log_tag, :
|
|
82
|
+
:max_request_size_bytes, :logger, :log_tag, :current_platform
|
|
94
83
|
attr_reader :log_level
|
|
95
84
|
|
|
96
85
|
def initialize
|
|
@@ -108,31 +97,9 @@ module Judoscale
|
|
|
108
97
|
|
|
109
98
|
self.class.adapter_configs.each(&:reset)
|
|
110
99
|
|
|
111
|
-
@
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
elsif ENV.include?("DYNO")
|
|
115
|
-
RuntimeContainer.new ENV["DYNO"]
|
|
116
|
-
elsif ENV.include?("RENDER_INSTANCE_ID")
|
|
117
|
-
# Deprecated API url using the service ID for legacy render services not using `JUDOSCALE_URL`.
|
|
118
|
-
@api_base_url ||= "https://adapter.judoscale.com/api/#{ENV["RENDER_SERVICE_ID"]}"
|
|
119
|
-
|
|
120
|
-
instance = ENV["RENDER_INSTANCE_ID"].delete_prefix("#{ENV["RENDER_SERVICE_ID"]}-")
|
|
121
|
-
RuntimeContainer.new instance
|
|
122
|
-
elsif ENV.include?("ECS_CONTAINER_METADATA_URI")
|
|
123
|
-
instance = ENV["ECS_CONTAINER_METADATA_URI"].split("/").last
|
|
124
|
-
RuntimeContainer.new instance
|
|
125
|
-
elsif ENV.include?("FLY_MACHINE_ID")
|
|
126
|
-
RuntimeContainer.new ENV["FLY_MACHINE_ID"]
|
|
127
|
-
elsif ENV.include?("RAILWAY_REPLICA_ID")
|
|
128
|
-
RuntimeContainer.new ENV["RAILWAY_REPLICA_ID"]
|
|
129
|
-
elsif ENV.include?("CONTAINER")
|
|
130
|
-
# Scalingo exposes the container type and index (e.g. "web-1") via CONTAINER.
|
|
131
|
-
RuntimeContainer.new ENV["CONTAINER"]
|
|
132
|
-
else
|
|
133
|
-
# Unsupported platform...
|
|
134
|
-
RuntimeContainer.new("")
|
|
135
|
-
end
|
|
100
|
+
@current_platform = Platform.detect(ENV)
|
|
101
|
+
# Legacy Render services not using JUDOSCALE_URL derive the API url from the platform.
|
|
102
|
+
@api_base_url ||= @current_platform.default_api_base_url
|
|
136
103
|
end
|
|
137
104
|
|
|
138
105
|
def log_level=(new_level)
|
|
@@ -9,7 +9,7 @@ module Judoscale
|
|
|
9
9
|
include Judoscale::Logger
|
|
10
10
|
|
|
11
11
|
def self.collect?(config)
|
|
12
|
-
super && !config.
|
|
12
|
+
super && !config.current_platform.redundant_instance? && adapter_config.enabled
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def self.adapter_name
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Judoscale
|
|
4
|
+
# The hosting platform we detected from the environment. The container/instance
|
|
5
|
+
# id is just one property of the platform — behavior that only applies to
|
|
6
|
+
# certain platforms (whether an instance is a redundant member of a formation,
|
|
7
|
+
# or an ephemeral process) lives on the platform subclasses that actually have
|
|
8
|
+
# those concepts, instead of being re-derived from the shape of the container
|
|
9
|
+
# string.
|
|
10
|
+
class Platform
|
|
11
|
+
attr_reader :container
|
|
12
|
+
|
|
13
|
+
def initialize(container)
|
|
14
|
+
@container = container.to_s
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Most platforms expose opaque, non-ordinal instance ids (Render, ECS, Fly,
|
|
18
|
+
# Railway, custom), so by default no instance is redundant or ephemeral.
|
|
19
|
+
# Platforms that have those concepts override these.
|
|
20
|
+
def redundant_instance?
|
|
21
|
+
false
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def ephemeral_instance?
|
|
25
|
+
false
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Platforms may contribute a default API base url when one isn't configured.
|
|
29
|
+
def default_api_base_url
|
|
30
|
+
nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Detect the current platform from the environment. Order matters: an explicit
|
|
34
|
+
# JUDOSCALE_CONTAINER always wins, and Unknown is the fallback.
|
|
35
|
+
def self.detect(env = ENV)
|
|
36
|
+
if env.include?("JUDOSCALE_CONTAINER")
|
|
37
|
+
Custom.new env["JUDOSCALE_CONTAINER"]
|
|
38
|
+
elsif env.include?("DYNO")
|
|
39
|
+
Heroku.new env["DYNO"]
|
|
40
|
+
elsif env.include?("RENDER_INSTANCE_ID")
|
|
41
|
+
Render.new env["RENDER_INSTANCE_ID"], service_id: env["RENDER_SERVICE_ID"]
|
|
42
|
+
elsif env.include?("ECS_CONTAINER_METADATA_URI")
|
|
43
|
+
Ecs.new env["ECS_CONTAINER_METADATA_URI"].split("/").last
|
|
44
|
+
elsif env.include?("FLY_MACHINE_ID")
|
|
45
|
+
Fly.new env["FLY_MACHINE_ID"]
|
|
46
|
+
elsif env.include?("RAILWAY_REPLICA_ID")
|
|
47
|
+
Railway.new env["RAILWAY_REPLICA_ID"]
|
|
48
|
+
elsif env.include?("CONTAINER")
|
|
49
|
+
# Scalingo exposes the container type and index (e.g. "web-1") via CONTAINER.
|
|
50
|
+
Scalingo.new env["CONTAINER"]
|
|
51
|
+
else
|
|
52
|
+
Unknown.new ""
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Heroku dynos are named "web.2". We collect job metrics from a single
|
|
57
|
+
# container per process type, so any instance beyond the first is redundant —
|
|
58
|
+
# it would only duplicate the queue metrics the first instance already reports.
|
|
59
|
+
class Heroku < Platform
|
|
60
|
+
def redundant_instance?
|
|
61
|
+
match = container.match(/\A[a-z_]+\.(\d+)\z/)
|
|
62
|
+
match ? match[1].to_i > 1 : false
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Heroku release phase and one-off dynos are named "release.1234" and "run.1234".
|
|
66
|
+
def ephemeral_instance?
|
|
67
|
+
normalized_container = container.downcase
|
|
68
|
+
normalized_container.start_with?("release.", "run.")
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Scalingo containers are named "web-2", same redundancy rule as Heroku.
|
|
73
|
+
class Scalingo < Platform
|
|
74
|
+
def redundant_instance?
|
|
75
|
+
match = container.match(/\A[a-z_]+-(\d+)\z/)
|
|
76
|
+
match ? match[1].to_i > 1 : false
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Scalingo one-off containers are named "one-off-1234".
|
|
80
|
+
def ephemeral_instance?
|
|
81
|
+
container.start_with?("one-off-")
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class Render < Platform
|
|
86
|
+
def initialize(instance_id, service_id:)
|
|
87
|
+
@service_id = service_id
|
|
88
|
+
# Render prefixes the instance id with the service id, which isn't part of the instance.
|
|
89
|
+
super(instance_id.delete_prefix("#{service_id}-"))
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Legacy Render services not using JUDOSCALE_URL derive the adapter URL
|
|
93
|
+
# from the service id.
|
|
94
|
+
def default_api_base_url
|
|
95
|
+
"https://adapter.judoscale.com/api/#{@service_id}"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
class Ecs < Platform
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class Fly < Platform
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
class Railway < Platform
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# User-provided container id via JUDOSCALE_CONTAINER.
|
|
109
|
+
class Custom < Platform
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Unsupported or undetected platform.
|
|
113
|
+
class Unknown < Platform
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
data/lib/judoscale/report.rb
CHANGED
|
@@ -12,7 +12,7 @@ module Judoscale
|
|
|
12
12
|
|
|
13
13
|
def as_json
|
|
14
14
|
{
|
|
15
|
-
container: config.
|
|
15
|
+
container: config.current_platform.container,
|
|
16
16
|
pid: Process.pid,
|
|
17
17
|
config: config.as_json,
|
|
18
18
|
adapters: adapters.reduce({}) { |hash, adapter| hash.merge!(adapter.as_json) },
|
data/lib/judoscale/reporter.rb
CHANGED
|
@@ -19,6 +19,11 @@ module Judoscale
|
|
|
19
19
|
def start!(config, adapters)
|
|
20
20
|
@pid = Process.pid
|
|
21
21
|
|
|
22
|
+
if config.current_platform.ephemeral_instance?
|
|
23
|
+
logger.debug "Reporter not started: in an ephemeral container"
|
|
24
|
+
return
|
|
25
|
+
end
|
|
26
|
+
|
|
22
27
|
if config.api_base_url.nil? || config.api_base_url.strip.empty?
|
|
23
28
|
logger.debug "Set api_base_url to enable metrics reporting"
|
|
24
29
|
return
|
data/lib/judoscale/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: judoscale-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.13.
|
|
4
|
+
version: 1.13.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Adam McCrea
|
|
@@ -40,6 +40,7 @@ files:
|
|
|
40
40
|
- lib/judoscale/metric.rb
|
|
41
41
|
- lib/judoscale/metrics_collector.rb
|
|
42
42
|
- lib/judoscale/metrics_store.rb
|
|
43
|
+
- lib/judoscale/platform.rb
|
|
43
44
|
- lib/judoscale/report.rb
|
|
44
45
|
- lib/judoscale/reporter.rb
|
|
45
46
|
- lib/judoscale/request_metrics.rb
|