judoscale-rails 1.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8126459482ea24a61ab251dc19235c8c52f3087d9104ff68d1442e4fb73d4698
4
- data.tar.gz: 3a25a9b8ced78ffdb8d21351085ccadfb533ecddda22b735b37c8d278977e88d
3
+ metadata.gz: 5af8c7881148adca3b0b924b30918cc0a99962c71d02c54b4ea66a19313c3845
4
+ data.tar.gz: 061baca32fd8dc5f05ff67524e7147d9cb803c9a3966935ff764141215a2d382
5
5
  SHA512:
6
- metadata.gz: b23c16010590b9270a1b1369e95b64eac963993391dfeb415a7e37544d2c06e199d562014b4aa9226087a5ae34c38ae60ba43d59e9455efa60789e71bcc4046c
7
- data.tar.gz: a3af90edce5f9b7124dea6d4e599f2c1543f6655fe50cfe341ece06e15e9dd4738671f0886270fd2dd5f791165924018a3cd86da89c789ae4fab3cd861c81a8a
6
+ metadata.gz: 58163866506c2ef25a3306a344f96ffa41ce83c8d3802e249b4914601e2787eb160e3509507c10bd73da6a86fbde08212547875f7239526bb3fcc95aa0da7da8
7
+ data.tar.gz: 3de499c651b8744a05911834bcc40a85340ea2c4b6cbe7f480c6afd126bf5cc21996563b2e85c57109015c5f1e4a4be57fa4d2860f633891b72c84067c7b5f36
@@ -3,12 +3,15 @@ require "judoscale/config"
3
3
  module Judoscale
4
4
  module Rails
5
5
  module Config
6
- attr_accessor :start_reporter_after_initialize, :rake_task_ignore_regex
6
+ attr_accessor :start_reporter_after_initialize, :rake_task_ignore_regex, :utilization_enabled, :utilization_interval
7
7
 
8
8
  def reset
9
9
  super
10
10
  @start_reporter_after_initialize = true
11
11
  @rake_task_ignore_regex = /assets:|db:/
12
+
13
+ @utilization_enabled = ENV["JUDOSCALE_UTILIZATION_ENABLED"] == "true"
14
+ @utilization_interval = (ENV["JUDOSCALE_UTILIZATION_INTERVAL"] || 1.0).to_f
12
15
  end
13
16
  end
14
17
 
@@ -4,6 +4,7 @@ require "rails"
4
4
  require "rails/railtie"
5
5
  require "judoscale/request_middleware"
6
6
  require "judoscale/rails/config"
7
+ require "judoscale/rails/utilization_middleware"
7
8
  require "judoscale/logger"
8
9
  require "judoscale/reporter"
9
10
 
@@ -27,14 +28,20 @@ module Judoscale
27
28
  ::Judoscale::Config.instance
28
29
  end
29
30
 
30
- initializer "Judoscale.logger" do |app|
31
+ initializer "judoscale.logger" do |app|
31
32
  judoscale_config.logger = ::Rails.logger
32
33
  end
33
34
 
34
- initializer "Judoscale.request_middleware" do |app|
35
+ initializer "judoscale.request_middleware" do |app|
35
36
  app.middleware.insert_before Rack::Runtime, RequestMiddleware
36
37
  end
37
38
 
39
+ initializer "judoscale.utilization_middleware", after: :load_config_initializers do |app|
40
+ if judoscale_config.utilization_enabled
41
+ app.middleware.insert_before RequestMiddleware, UtilizationMiddleware, interval: judoscale_config.utilization_interval
42
+ end
43
+ end
44
+
38
45
  config.after_initialize do
39
46
  if in_rails_console_or_runner?
40
47
  logger.debug "No reporting since we're in a Rails console or runner process"
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+ require "concurrent"
5
+ require "judoscale/metrics_store"
6
+
7
+ module Judoscale
8
+ module Rails
9
+ class UtilizationMiddleware
10
+ def initialize(app, interval:)
11
+ @app = app
12
+ @interval = interval
13
+ end
14
+
15
+ def call(env)
16
+ tracker = UtilizationTracker.instance
17
+ tracker.start!(interval: @interval)
18
+ tracker.incr
19
+
20
+ @app.call(env)
21
+ ensure
22
+ tracker.decr
23
+ end
24
+ end
25
+
26
+ class UtilizationTracker
27
+ include Singleton
28
+
29
+ def initialize
30
+ @active_request_counter = Concurrent::AtomicFixnum.new(0)
31
+ @thread_ref = Concurrent::AtomicReference.new(nil)
32
+ end
33
+
34
+ def start!(interval:)
35
+ @thread_ref.update do |current_thread|
36
+ next current_thread if current_thread&.alive?
37
+
38
+ Thread.new do
39
+ # Advise multi-threaded app servers to ignore this thread for the purposes of fork safety warnings.
40
+ Thread.current.thread_variable_set(:fork_safe, true)
41
+
42
+ loop do
43
+ sleep interval
44
+ track_current_state
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ def incr
51
+ @active_request_counter.increment
52
+ end
53
+
54
+ def decr
55
+ @active_request_counter.decrement
56
+ end
57
+
58
+ def track_current_state
59
+ active_requests = @active_request_counter.value
60
+ active_processes = (active_requests > 0) ? 1 : 0
61
+ time = Time.now.utc
62
+
63
+ MetricsStore.instance.tap do |store|
64
+ store.push :pu, active_processes, time # pu = process utilization
65
+ store.push :ru, active_requests, time # ru = request utilization
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: judoscale-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.0
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-02-17 00:00:00.000000000 Z
13
+ date: 2025-04-28 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: judoscale-ruby
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - '='
20
20
  - !ruby/object:Gem::Version
21
- version: 1.10.0
21
+ version: 1.11.0
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - '='
27
27
  - !ruby/object:Gem::Version
28
- version: 1.10.0
28
+ version: 1.11.0
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: railties
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -51,6 +51,7 @@ files:
51
51
  - lib/judoscale/rails.rb
52
52
  - lib/judoscale/rails/config.rb
53
53
  - lib/judoscale/rails/railtie.rb
54
+ - lib/judoscale/rails/utilization_middleware.rb
54
55
  homepage: https://judoscale.com
55
56
  licenses:
56
57
  - MIT