judoscale-ruby 1.9.0 → 1.11.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/lib/judoscale/config.rb +4 -2
- data/lib/judoscale/request_metrics.rb +40 -30
- data/lib/judoscale/request_middleware.rb +14 -11
- data/lib/judoscale/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 92983f008bba242830346f573d60a9c7302c794cac38afbc0e78b359e4dd09e2
|
4
|
+
data.tar.gz: 0c7971f58dab5fa1c17b43e14f25db639d5d81b2b0b2dc60e123e6951f0f645c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5452b651fe1582de5c6ae1c96f78738b30d2090635df3701a1e8d987f19ac0c6d9cb6a408cafcea62e0208616a5a11680919cb42695ef01023887980a4fa71c
|
7
|
+
data.tar.gz: c63a089e0f391605166f7c65b2b0afd457bb05fde10a7c9cd1a1cf67641f67721f5a08f5005c38b8057ac4a7877738917506b2e724ff40a728263613f70f6888
|
data/lib/judoscale/config.rb
CHANGED
@@ -35,8 +35,8 @@ module Judoscale
|
|
35
35
|
@queue_filter = DEFAULT_QUEUE_FILTER
|
36
36
|
|
37
37
|
# Support for deprecated legacy env var configs.
|
38
|
-
@max_queues = (ENV["RAILS_AUTOSCALE_MAX_QUEUES"] || 20).to_i
|
39
|
-
self.track_busy_jobs = ENV["RAILS_AUTOSCALE_LONG_JOBS"] == "true"
|
38
|
+
@max_queues = (ENV["JUDOSCALE_MAX_QUEUES"] || ENV["RAILS_AUTOSCALE_MAX_QUEUES"] || 20).to_i
|
39
|
+
self.track_busy_jobs = (ENV["JUDOSCALE_LONG_JOBS"] || ENV["RAILS_AUTOSCALE_LONG_JOBS"]) == "true"
|
40
40
|
end
|
41
41
|
|
42
42
|
def track_busy_jobs=(value)
|
@@ -105,6 +105,8 @@ module Judoscale
|
|
105
105
|
elsif ENV.include?("ECS_CONTAINER_METADATA_URI")
|
106
106
|
instance = ENV["ECS_CONTAINER_METADATA_URI"].split("/").last
|
107
107
|
RuntimeContainer.new instance
|
108
|
+
elsif ENV.include?("FLY_MACHINE_ID")
|
109
|
+
RuntimeContainer.new ENV["FLY_MACHINE_ID"]
|
108
110
|
elsif ENV.include?("RAILWAY_REPLICA_ID")
|
109
111
|
RuntimeContainer.new ENV["RAILWAY_REPLICA_ID"]
|
110
112
|
else
|
@@ -16,39 +16,12 @@ module Judoscale
|
|
16
16
|
@request_start_header = env["HTTP_X_REQUEST_START"]
|
17
17
|
end
|
18
18
|
|
19
|
-
def
|
20
|
-
@
|
21
|
-
end
|
22
|
-
|
23
|
-
def started_at
|
24
|
-
if @request_start_header
|
25
|
-
# There are several variants of this header. We handle these:
|
26
|
-
# - whole milliseconds (Heroku)
|
27
|
-
# - whole microseconds (???)
|
28
|
-
# - whole nanoseconds (Render)
|
29
|
-
# - fractional seconds (NGINX)
|
30
|
-
# - preceeding "t=" (NGINX)
|
31
|
-
value = @request_start_header.gsub(/[^0-9.]/, "").to_f
|
32
|
-
|
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)
|
44
|
-
end
|
45
|
-
end
|
19
|
+
def track_queue_time?
|
20
|
+
@request_start_header && !ignore_large_request?
|
46
21
|
end
|
47
22
|
|
48
23
|
def queue_time(now = Time.now)
|
49
|
-
|
50
|
-
|
51
|
-
queue_time = ((now - started_at) * 1000).to_i
|
24
|
+
queue_time = ((now.utc - started_at.utc) * 1000).to_i
|
52
25
|
|
53
26
|
# Subtract the time Puma spent waiting on the request body, i.e. the network time. It's irrelevant to
|
54
27
|
# capacity-related queue time. Without this, slow clients and large request payloads will skew queue time.
|
@@ -57,5 +30,42 @@ module Judoscale
|
|
57
30
|
# Safeguard against negative queue times (should not happen in practice)
|
58
31
|
(queue_time > 0) ? queue_time : 0
|
59
32
|
end
|
33
|
+
|
34
|
+
def elapsed_time
|
35
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
36
|
+
response = yield
|
37
|
+
finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
38
|
+
|
39
|
+
elapsed = ((finish - start) * 1000).to_i
|
40
|
+
[elapsed, response]
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def ignore_large_request?
|
46
|
+
@config.ignore_large_requests? && @size > @config.max_request_size_bytes
|
47
|
+
end
|
48
|
+
|
49
|
+
def started_at
|
50
|
+
# There are several variants of this header. We handle these:
|
51
|
+
# - whole milliseconds (Heroku)
|
52
|
+
# - whole microseconds (???)
|
53
|
+
# - whole nanoseconds (Render)
|
54
|
+
# - fractional seconds (NGINX)
|
55
|
+
# - preceeding "t=" (NGINX)
|
56
|
+
value = @request_start_header.gsub(/[^0-9.]/, "").to_f
|
57
|
+
|
58
|
+
# `value` could be seconds, milliseconds, microseconds or nanoseconds.
|
59
|
+
# We use some arbitrary cutoffs to determine which one it is.
|
60
|
+
if value > NANOSECONDS_CUTOFF
|
61
|
+
Time.at(value / 1_000_000_000.0)
|
62
|
+
elsif value > MICROSECONDS_CUTOFF
|
63
|
+
Time.at(value / 1_000_000.0)
|
64
|
+
elsif value > MILLISECONDS_CUTOFF
|
65
|
+
Time.at(value / 1000.0)
|
66
|
+
else
|
67
|
+
Time.at(value)
|
68
|
+
end
|
69
|
+
end
|
60
70
|
end
|
61
71
|
end
|
@@ -15,30 +15,33 @@ module Judoscale
|
|
15
15
|
|
16
16
|
def call(env)
|
17
17
|
request_metrics = RequestMetrics.new(env)
|
18
|
+
store = MetricsStore.instance
|
19
|
+
time = Time.now.utc
|
18
20
|
|
19
|
-
|
20
|
-
queue_time = request_metrics.queue_time
|
21
|
+
if request_metrics.track_queue_time?
|
22
|
+
queue_time = request_metrics.queue_time(time)
|
21
23
|
network_time = request_metrics.network_time
|
22
|
-
end
|
23
|
-
|
24
|
-
Reporter.start
|
25
|
-
|
26
|
-
if queue_time
|
27
|
-
store = MetricsStore.instance
|
28
24
|
|
29
25
|
# NOTE: Expose queue time to the app
|
30
26
|
env["judoscale.queue_time"] = queue_time
|
31
|
-
store.push :qt, queue_time
|
27
|
+
store.push :qt, queue_time, time
|
32
28
|
|
33
29
|
unless network_time.zero?
|
34
30
|
env["judoscale.network_time"] = network_time
|
35
|
-
store.push :nt, network_time
|
31
|
+
store.push :nt, network_time, time
|
36
32
|
end
|
37
33
|
|
38
34
|
logger.debug "Request queue_time=#{queue_time}ms network_time=#{network_time}ms request_id=#{request_metrics.request_id} size=#{request_metrics.size}"
|
39
35
|
end
|
40
36
|
|
41
|
-
|
37
|
+
Reporter.start
|
38
|
+
|
39
|
+
app_time, response = request_metrics.elapsed_time do
|
40
|
+
@app.call(env)
|
41
|
+
end
|
42
|
+
store.push :at, app_time, time
|
43
|
+
|
44
|
+
response
|
42
45
|
end
|
43
46
|
end
|
44
47
|
end
|
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.
|
4
|
+
version: 1.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam McCrea
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2025-
|
13
|
+
date: 2025-04-28 00:00:00.000000000 Z
|
14
14
|
dependencies: []
|
15
15
|
description:
|
16
16
|
email:
|