rage-rb 1.26.1 → 1.28.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/CHANGELOG.md +30 -1
- data/CONTRIBUTING.md +10 -1
- data/README.md +1 -1
- data/exe/rage +1 -1
- data/lib/rage/cable/channel.rb +7 -11
- data/lib/rage/cli/base.rb +27 -0
- data/lib/rage/cli/code_generator.rb +58 -0
- data/lib/rage/cli/new_app_generator.rb +66 -0
- data/lib/rage/cli/openapi.rb +20 -0
- data/lib/rage/cli/skills.rb +222 -220
- data/lib/rage/cli.rb +12 -143
- data/lib/rage/code_loader.rb +5 -1
- data/lib/rage/configuration.rb +73 -2
- data/lib/rage/cookies.rb +11 -9
- data/lib/rage/daemon.rb +5 -2
- data/lib/rage/deferred/backends/disk.rb +544 -199
- data/lib/rage/deferred/backends/nil.rb +16 -2
- data/lib/rage/deferred/deferred.rb +5 -1
- data/lib/rage/deferred/queue.rb +8 -3
- data/lib/rage/deferred/task.rb +1 -0
- data/lib/rage/fiber_scheduler.rb +17 -13
- data/lib/rage/hooks.rb +6 -1
- data/lib/rage/logger/logger.rb +55 -4
- data/lib/rage/openapi/index.html.erb +1 -1
- data/lib/rage/openapi/openapi.rb +14 -5
- data/lib/rage/openapi/parsers/ext/blueprinter.rb +20 -12
- data/lib/rage/router/README.md +1 -1
- data/lib/rage/router/backend.rb +8 -4
- data/lib/rage/router/dsl.rb +5 -7
- data/lib/rage/tasks.rb +5 -0
- data/lib/rage/telemetry/capacity.rb +42 -0
- data/lib/rage/telemetry/telemetry.rb +19 -0
- data/lib/rage/version.rb +1 -1
- data/lib/rage-rb.rb +3 -0
- metadata +8 -3
data/lib/rage/cli.rb
CHANGED
|
@@ -4,65 +4,14 @@ require "thor"
|
|
|
4
4
|
require "rack"
|
|
5
5
|
require "rage/version"
|
|
6
6
|
|
|
7
|
+
require "rage/cli/base"
|
|
7
8
|
require "rage/cli/skills"
|
|
9
|
+
require "rage/cli/openapi"
|
|
10
|
+
require "rage/cli/code_generator"
|
|
11
|
+
require "rage/cli/new_app_generator"
|
|
8
12
|
|
|
9
|
-
module Rage
|
|
10
|
-
class
|
|
11
|
-
include Thor::Actions
|
|
12
|
-
|
|
13
|
-
def self.source_root
|
|
14
|
-
File.expand_path("templates", __dir__)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
desc "migration NAME", "Generate a new migration"
|
|
18
|
-
def migration(name = nil)
|
|
19
|
-
return help("migration") if name.nil?
|
|
20
|
-
|
|
21
|
-
setup
|
|
22
|
-
Rake::Task["db:new_migration"].invoke(name)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
desc "model NAME", "Generate a new model"
|
|
26
|
-
def model(name = nil)
|
|
27
|
-
return help("model") if name.nil?
|
|
28
|
-
|
|
29
|
-
setup
|
|
30
|
-
migration("create_#{name.pluralize}")
|
|
31
|
-
@model_name = name.classify
|
|
32
|
-
template("model-template/model.rb", "app/models/#{name.singularize.underscore}.rb")
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
desc "controller NAME", "Generate a new controller"
|
|
36
|
-
def controller(name = nil)
|
|
37
|
-
return help("controller") if name.nil?
|
|
38
|
-
|
|
39
|
-
setup
|
|
40
|
-
unless defined?(ActiveSupport::Inflector)
|
|
41
|
-
raise LoadError, <<~ERR
|
|
42
|
-
ActiveSupport::Inflector is required to run this command. Add the following line to your Gemfile:
|
|
43
|
-
gem "activesupport", require: "active_support/inflector"
|
|
44
|
-
ERR
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# remove trailing Controller if already present
|
|
48
|
-
normalized_name = name.sub(/_?controller$/i, "")
|
|
49
|
-
@controller_name = "#{normalized_name.camelize}Controller"
|
|
50
|
-
file_name = "#{normalized_name.underscore}_controller.rb"
|
|
51
|
-
|
|
52
|
-
template("controller-template/controller.rb", "app/controllers/#{file_name}")
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
private
|
|
56
|
-
|
|
57
|
-
def setup
|
|
58
|
-
@setup ||= begin
|
|
59
|
-
require "rake"
|
|
60
|
-
load "Rakefile"
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
class CLI < Thor
|
|
13
|
+
module Rage::CLI
|
|
14
|
+
class App < Base
|
|
66
15
|
def self.exit_on_failure?
|
|
67
16
|
true
|
|
68
17
|
end
|
|
@@ -74,7 +23,7 @@ module Rage
|
|
|
74
23
|
return help("new") if options.help? || path.nil?
|
|
75
24
|
|
|
76
25
|
require "rage/all"
|
|
77
|
-
|
|
26
|
+
NewAppGenerator.start([path, options[:database]])
|
|
78
27
|
end
|
|
79
28
|
|
|
80
29
|
desc "s", "Start the app server"
|
|
@@ -232,11 +181,14 @@ module Rage
|
|
|
232
181
|
end
|
|
233
182
|
|
|
234
183
|
desc "skills", "Manage coding agent skills"
|
|
235
|
-
subcommand "skills",
|
|
184
|
+
subcommand "skills", Skills
|
|
185
|
+
|
|
186
|
+
desc "openapi", "OpenAPI validation tools"
|
|
187
|
+
subcommand "openapi", OpenAPI
|
|
236
188
|
|
|
237
189
|
map "generate" => :g
|
|
238
190
|
desc "g TYPE", "Generate new code"
|
|
239
|
-
subcommand "g",
|
|
191
|
+
subcommand "g", CodeGenerator
|
|
240
192
|
|
|
241
193
|
map "--tasks" => :tasks
|
|
242
194
|
desc "--tasks", "See the list of available tasks"
|
|
@@ -273,26 +225,6 @@ module Rage
|
|
|
273
225
|
|
|
274
226
|
private
|
|
275
227
|
|
|
276
|
-
def environment
|
|
277
|
-
require File.expand_path("config/application.rb", Dir.pwd)
|
|
278
|
-
|
|
279
|
-
if Rage.config.internal.rails_mode
|
|
280
|
-
require File.expand_path("config/environment.rb", Dir.pwd)
|
|
281
|
-
end
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
def set_env(options)
|
|
285
|
-
if options[:environment]
|
|
286
|
-
ENV["RAGE_ENV"] = ENV["RAILS_ENV"] = options[:environment]
|
|
287
|
-
elsif ENV["RAGE_ENV"]
|
|
288
|
-
ENV["RAILS_ENV"] = ENV["RAGE_ENV"]
|
|
289
|
-
elsif ENV["RAILS_ENV"]
|
|
290
|
-
ENV["RAGE_ENV"] = ENV["RAILS_ENV"]
|
|
291
|
-
else
|
|
292
|
-
ENV["RAGE_ENV"] = ENV["RAILS_ENV"] = "development"
|
|
293
|
-
end
|
|
294
|
-
end
|
|
295
|
-
|
|
296
228
|
def linked_rake_tasks
|
|
297
229
|
require "rake"
|
|
298
230
|
Rake::TaskManager.record_task_metadata = true
|
|
@@ -371,67 +303,4 @@ module Rage
|
|
|
371
303
|
end
|
|
372
304
|
end
|
|
373
305
|
end
|
|
374
|
-
|
|
375
|
-
class CLINewAppGenerator < Thor::Group
|
|
376
|
-
include Thor::Actions
|
|
377
|
-
argument :path, type: :string
|
|
378
|
-
argument :database, type: :string, required: false
|
|
379
|
-
|
|
380
|
-
def self.source_root
|
|
381
|
-
File.expand_path("templates", __dir__)
|
|
382
|
-
end
|
|
383
|
-
|
|
384
|
-
def setup
|
|
385
|
-
@use_database = !database.nil?
|
|
386
|
-
end
|
|
387
|
-
|
|
388
|
-
def create_directory
|
|
389
|
-
empty_directory(path)
|
|
390
|
-
end
|
|
391
|
-
|
|
392
|
-
def copy_files
|
|
393
|
-
inject_templates
|
|
394
|
-
end
|
|
395
|
-
|
|
396
|
-
def install_database
|
|
397
|
-
return unless @use_database
|
|
398
|
-
|
|
399
|
-
@app_name = path.tr("-", "_").downcase
|
|
400
|
-
append_to_file "#{path}/Gemfile", <<~RUBY
|
|
401
|
-
|
|
402
|
-
gem "#{get_db_gem_name}"
|
|
403
|
-
gem "activerecord"
|
|
404
|
-
gem "standalone_migrations", require: false
|
|
405
|
-
RUBY
|
|
406
|
-
|
|
407
|
-
inject_templates("db-templates")
|
|
408
|
-
inject_templates("db-templates/#{database}")
|
|
409
|
-
end
|
|
410
|
-
|
|
411
|
-
private
|
|
412
|
-
|
|
413
|
-
def inject_templates(from = nil)
|
|
414
|
-
root = "#{self.class.source_root}/#{from}"
|
|
415
|
-
|
|
416
|
-
Dir.glob("*", base: root).each do |template|
|
|
417
|
-
next if File.directory?("#{root}/#{template}")
|
|
418
|
-
|
|
419
|
-
*template_path_parts, template_name = template.split("-")
|
|
420
|
-
template("#{root}/#{template}", [path, *template_path_parts, template_name].join("/"))
|
|
421
|
-
end
|
|
422
|
-
end
|
|
423
|
-
|
|
424
|
-
def get_db_gem_name
|
|
425
|
-
case database
|
|
426
|
-
when "mysql"
|
|
427
|
-
"mysql2"
|
|
428
|
-
when "trilogy"
|
|
429
|
-
"trilogy"
|
|
430
|
-
when "postgresql"
|
|
431
|
-
"pg"
|
|
432
|
-
when "sqlite3"
|
|
433
|
-
"sqlite3"
|
|
434
|
-
end
|
|
435
|
-
end
|
|
436
|
-
end
|
|
437
306
|
end
|
data/lib/rage/code_loader.rb
CHANGED
|
@@ -37,6 +37,7 @@ class Rage::CodeLoader
|
|
|
37
37
|
load("#{Rage.root}/config/routes.rb")
|
|
38
38
|
|
|
39
39
|
reload_components
|
|
40
|
+
Rage.config.run_hooks_for(:after_reload)
|
|
40
41
|
end
|
|
41
42
|
|
|
42
43
|
# in Rails mode - reset the routes; everything else will be done by Rails
|
|
@@ -47,6 +48,7 @@ class Rage::CodeLoader
|
|
|
47
48
|
Rage.__router.reset_routes
|
|
48
49
|
|
|
49
50
|
reload_components
|
|
51
|
+
Rage.config.run_hooks_for(:after_reload)
|
|
50
52
|
end
|
|
51
53
|
|
|
52
54
|
def reloading?
|
|
@@ -54,7 +56,9 @@ class Rage::CodeLoader
|
|
|
54
56
|
end
|
|
55
57
|
|
|
56
58
|
def check_updated!
|
|
57
|
-
current_watched = @autoload_path.glob("**/*.rb") + Rage.root.glob("config/routes.rb") + Rage.root.glob("config/openapi_components.*")
|
|
59
|
+
current_watched = @autoload_path.glob("**/*.{rb,erb}") + Rage.root.glob("config/routes.rb") + Rage.root.glob("config/openapi_components.*")
|
|
60
|
+
current_watched += Rage.config.code_loader.reload_paths.flat_map { |pattern| Rage.root.glob(pattern) }
|
|
61
|
+
|
|
58
62
|
current_update_at = current_watched.max_by { |path| path.exist? ? path.mtime.to_f : 0 }&.mtime.to_f
|
|
59
63
|
return false if !@last_watched && !@last_update_at
|
|
60
64
|
|
data/lib/rage/configuration.rb
CHANGED
|
@@ -23,6 +23,7 @@ require "erb"
|
|
|
23
23
|
# - _RAGE_DISABLE_IO_WRITE_ - disables the `io_write` hook to fix the ["zero-length iov"](https://bugs.ruby-lang.org/issues/19640) error on Ruby < 3.3.
|
|
24
24
|
# - _RAGE_DISABLE_AR_POOL_PATCH_ - disables the `ActiveRecord::ConnectionPool` patch and makes Rage use the original ActiveRecord implementation.
|
|
25
25
|
# - _RAGE_DISABLE_AR_WEAK_CONNECTIONS_ - instructs Rage to not reuse Active Record connections between different fibers. Only applies to Active Record < 7.2.
|
|
26
|
+
# - _RAGE_ENABLE_NON_BLOCKING_TIMEOUT_ - enables the non-blocking `timeout_after` method on the fiber scheduler, which allows timeouts to work cooperatively with fiber-based concurrency.
|
|
26
27
|
#
|
|
27
28
|
class Rage::Configuration
|
|
28
29
|
# @private
|
|
@@ -140,6 +141,15 @@ class Rage::Configuration
|
|
|
140
141
|
push_hook(block, :after_initialize)
|
|
141
142
|
end
|
|
142
143
|
|
|
144
|
+
# Schedule a block of code to run after Rage has reloaded the application code in development. Use this to reset state or re-initialize dependencies that cache application-level constants.
|
|
145
|
+
# @example
|
|
146
|
+
# Rage.config.after_reload do
|
|
147
|
+
# MyCache.clear
|
|
148
|
+
# end
|
|
149
|
+
def after_reload(&block)
|
|
150
|
+
push_hook(block, :after_reload)
|
|
151
|
+
end
|
|
152
|
+
|
|
143
153
|
# Register a custom renderer that generates overloads `render` on all controllers.
|
|
144
154
|
# The block receives the object passed to `render` together with any additional keyword arguments.
|
|
145
155
|
# The code inside the block is executed in the context of the controller instance, so you can access all usual controller methods in it.
|
|
@@ -255,6 +265,29 @@ class Rage::Configuration
|
|
|
255
265
|
def log_tags
|
|
256
266
|
@log_tags ||= LogTags.new
|
|
257
267
|
end
|
|
268
|
+
|
|
269
|
+
# Allows configuring case-insensitive partial matches for redacting structured log context keys.
|
|
270
|
+
# Matching keys will have their values replaced with `"[REDACTED]"` before the log entry is written.
|
|
271
|
+
#
|
|
272
|
+
# @param keys [String, Symbol, Array<String, Symbol>, nil] one or more keys to redact
|
|
273
|
+
# @example Redact common secrets from structured logs
|
|
274
|
+
# Rage.configure do
|
|
275
|
+
# config.log_redact_keys = [:password, :token, :secret]
|
|
276
|
+
# end
|
|
277
|
+
def log_redact_keys=(keys)
|
|
278
|
+
@log_redact_keys = Array(keys).filter_map { |key|
|
|
279
|
+
if !key.is_a?(String) && !key.is_a?(Symbol)
|
|
280
|
+
raise ArgumentError, "log redact keys have to be strings or symbols"
|
|
281
|
+
elsif !key.empty?
|
|
282
|
+
key.to_s
|
|
283
|
+
end
|
|
284
|
+
}.uniq
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# @private
|
|
288
|
+
def log_redact_keys
|
|
289
|
+
@log_redact_keys || []
|
|
290
|
+
end
|
|
258
291
|
# @!endgroup
|
|
259
292
|
|
|
260
293
|
# @!group Telemetry Configuration
|
|
@@ -281,6 +314,14 @@ class Rage::Configuration
|
|
|
281
314
|
end
|
|
282
315
|
# @!endgroup
|
|
283
316
|
|
|
317
|
+
# @!group Code Loader Configuration
|
|
318
|
+
# Allows configuring code loader settings.
|
|
319
|
+
# @return [Rage::Configuration::CodeLoader]
|
|
320
|
+
def code_loader
|
|
321
|
+
@code_loader ||= CodeLoader.new
|
|
322
|
+
end
|
|
323
|
+
# @!endgroup
|
|
324
|
+
|
|
284
325
|
# @!group Blocking Operation Pool Configuration
|
|
285
326
|
# Allows configuring the thread pool for offloading native calls.
|
|
286
327
|
# @return [Rage::Configuration::BlockingOperationPool]
|
|
@@ -434,7 +475,7 @@ class Rage::Configuration
|
|
|
434
475
|
# end
|
|
435
476
|
def <<(reporter)
|
|
436
477
|
validate_input!(reporter)
|
|
437
|
-
|
|
478
|
+
raise ArgumentError, "#{reporter} is already registered" if @objects.include?(reporter)
|
|
438
479
|
|
|
439
480
|
@objects << reporter
|
|
440
481
|
Rage::Errors.__send__(:__register_reporter, reporter)
|
|
@@ -877,6 +918,7 @@ class Rage::Configuration
|
|
|
877
918
|
@backend_options = parse_disk_backend_options(opts)
|
|
878
919
|
Rage::Deferred::Backends::Disk
|
|
879
920
|
when nil
|
|
921
|
+
@backend_options = {} if RUBY_VERSION.start_with?("3.3.")
|
|
880
922
|
Rage::Deferred::Backends::Nil
|
|
881
923
|
else
|
|
882
924
|
raise ArgumentError, "unsupported backend value; supported keys are `:disk` and `nil`"
|
|
@@ -1122,6 +1164,29 @@ class Rage::Configuration
|
|
|
1122
1164
|
attr_accessor :form_actions
|
|
1123
1165
|
end
|
|
1124
1166
|
|
|
1167
|
+
class CodeLoader
|
|
1168
|
+
# @private
|
|
1169
|
+
def initialize
|
|
1170
|
+
@reload_paths = []
|
|
1171
|
+
end
|
|
1172
|
+
|
|
1173
|
+
# @private
|
|
1174
|
+
attr_reader :reload_paths
|
|
1175
|
+
|
|
1176
|
+
# Specify additional paths to watch for changes in development.
|
|
1177
|
+
#
|
|
1178
|
+
# @param paths [Array<Pathname, String>] glob patterns or directory paths to watch
|
|
1179
|
+
# @example Watch HAML templates
|
|
1180
|
+
# Rage.configure do
|
|
1181
|
+
# config.code_loader.reload_paths = ["app/views/**/*.haml"]
|
|
1182
|
+
# end
|
|
1183
|
+
def reload_paths=(paths)
|
|
1184
|
+
@reload_paths = Array(paths).map do |path|
|
|
1185
|
+
path.is_a?(Pathname) ? path : Pathname.new(path)
|
|
1186
|
+
end
|
|
1187
|
+
end
|
|
1188
|
+
end
|
|
1189
|
+
|
|
1125
1190
|
class BlockingOperationPool
|
|
1126
1191
|
# @!attribute enabled
|
|
1127
1192
|
# Enable a background thread pool for offloading native calls that can be executed outside the GVL, freeing
|
|
@@ -1164,7 +1229,11 @@ class Rage::Configuration
|
|
|
1164
1229
|
# end
|
|
1165
1230
|
def <<(daemon)
|
|
1166
1231
|
validate!(daemon)
|
|
1232
|
+
raise ArgumentError, "#{daemon} is already registered" if @klasses.include?(daemon)
|
|
1233
|
+
|
|
1167
1234
|
@klasses << daemon
|
|
1235
|
+
|
|
1236
|
+
self
|
|
1168
1237
|
end
|
|
1169
1238
|
|
|
1170
1239
|
alias_method :push, :<<
|
|
@@ -1259,12 +1328,14 @@ class Rage::Configuration
|
|
|
1259
1328
|
if @logger
|
|
1260
1329
|
@logger.formatter = @log_formatter if @log_formatter
|
|
1261
1330
|
@logger.level = @log_level if @log_level
|
|
1331
|
+
@logger.log_redact_keys = @log_redact_keys if @log_redact_keys
|
|
1262
1332
|
else
|
|
1263
1333
|
@logger = Rage::Logger.new(nil)
|
|
1264
1334
|
end
|
|
1265
1335
|
|
|
1266
|
-
if @log_formatter && @logger.external_logger.is_a?(Rage::Logger::External::Dynamic)
|
|
1336
|
+
if @log_formatter && @logger.external_logger.is_a?(Rage::Logger::External::Dynamic) && !@log_formatter_warning_shown
|
|
1267
1337
|
puts "WARNING: changing the log formatter via `config.log_formatter=` has no effect when using a custom external logger."
|
|
1338
|
+
@log_formatter_warning_shown = true
|
|
1268
1339
|
end
|
|
1269
1340
|
|
|
1270
1341
|
if @log_context
|
data/lib/rage/cookies.rb
CHANGED
|
@@ -278,24 +278,22 @@ class Rage::Cookies
|
|
|
278
278
|
|
|
279
279
|
private
|
|
280
280
|
|
|
281
|
-
def ensure_rbnacl!
|
|
281
|
+
def ensure_rbnacl!
|
|
282
282
|
return if defined?(RbNaCl) &&
|
|
283
283
|
Gem::Version.create(RbNaCl::VERSION) >= RBNACL_MIN_VERSION &&
|
|
284
284
|
Gem::Version.create(RbNaCl::VERSION) < RBNACL_MAX_VERSION
|
|
285
285
|
|
|
286
286
|
fail <<~ERR
|
|
287
287
|
|
|
288
|
-
Rage depends on `rbnacl` [>= #{RBNACL_MIN_VERSION}, < #{RBNACL_MAX_VERSION}] to support
|
|
288
|
+
Rage depends on `rbnacl` [>= #{RBNACL_MIN_VERSION}, < #{RBNACL_MAX_VERSION}] to support encrypted and signed cookies. Ensure the following line is added to your Gemfile:
|
|
289
289
|
gem "rbnacl"
|
|
290
290
|
|
|
291
291
|
ERR
|
|
292
292
|
end
|
|
293
293
|
|
|
294
294
|
def build_key(secret, purpose:)
|
|
295
|
-
ensure_rbnacl!(purpose: purpose)
|
|
296
|
-
|
|
297
295
|
if !secret
|
|
298
|
-
raise "Rage.config.secret_key_base should be set to use
|
|
296
|
+
raise "Rage.config.secret_key_base should be set to use encrypted or signed cookies"
|
|
299
297
|
end
|
|
300
298
|
|
|
301
299
|
RbNaCl::Hash.blake2b("", key: [secret].pack("H*"), digest_size: 32, personal: purpose)
|
|
@@ -337,7 +335,10 @@ class Rage::Cookies
|
|
|
337
335
|
private
|
|
338
336
|
|
|
339
337
|
def primary_box
|
|
340
|
-
@primary_box ||=
|
|
338
|
+
@primary_box ||= begin
|
|
339
|
+
ensure_rbnacl!
|
|
340
|
+
RbNaCl::SimpleBox.from_secret_key(build_key(Rage.config.secret_key_base, purpose: PURPOSE))
|
|
341
|
+
end
|
|
341
342
|
end
|
|
342
343
|
|
|
343
344
|
def fallback_boxes
|
|
@@ -401,9 +402,10 @@ class Rage::Cookies
|
|
|
401
402
|
end
|
|
402
403
|
|
|
403
404
|
def primary_signer
|
|
404
|
-
@primary_signer ||=
|
|
405
|
-
|
|
406
|
-
|
|
405
|
+
@primary_signer ||= begin
|
|
406
|
+
ensure_rbnacl!
|
|
407
|
+
RbNaCl::HMAC::SHA512256.new(build_key(Rage.config.secret_key_base, purpose: PURPOSE))
|
|
408
|
+
end
|
|
407
409
|
end
|
|
408
410
|
|
|
409
411
|
def fallback_signers
|
data/lib/rage/daemon.rb
CHANGED
|
@@ -174,7 +174,6 @@ class Rage::Daemon
|
|
|
174
174
|
instance = new
|
|
175
175
|
result = instance.perform
|
|
176
176
|
break if result.equal?(Stop) || @__stopping
|
|
177
|
-
Rage.logger.warn("Daemon exited, restarting...")
|
|
178
177
|
rescue => e
|
|
179
178
|
break if @__stopping
|
|
180
179
|
Rage.logger.error("Daemon failed with exception: #{e.class} (#{e.message}):\n#{e.backtrace.join("\n")}")
|
|
@@ -185,7 +184,11 @@ class Rage::Daemon
|
|
|
185
184
|
|
|
186
185
|
# reset backoff if ran successfully for a while
|
|
187
186
|
backoff = INITIAL_BACKOFF if Process.clock_gettime(Process::CLOCK_MONOTONIC) - started_at > BACKOFF_RESET_INTERVAL
|
|
188
|
-
|
|
187
|
+
|
|
188
|
+
interval = (backoff / 2 + rand * backoff / 2).round(2)
|
|
189
|
+
Rage.logger.warn("Daemon exited, restarting in #{interval}s")
|
|
190
|
+
sleep(interval)
|
|
191
|
+
|
|
189
192
|
backoff = (backoff * 2).clamp(INITIAL_BACKOFF, MAX_BACKOFF)
|
|
190
193
|
end
|
|
191
194
|
end
|