Skip to content

Commit 5352f6f

Browse files
committed
Add Rage::Deferred
1 parent 86685d8 commit 5352f6f

8 files changed

Lines changed: 592 additions & 14 deletions

File tree

lib/rage-rb.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ def self.openapi
2222
Rage::OpenAPI
2323
end
2424

25+
def self.deferred
26+
Rage::Deferred
27+
end
28+
2529
def self.routes
2630
Rage::Router::DSL.new(__router)
2731
end
@@ -130,6 +134,7 @@ module ActiveRecord
130134
autoload :Session, "rage/session"
131135
autoload :Cable, "rage/cable/cable"
132136
autoload :OpenAPI, "rage/openapi/openapi"
137+
autoload :Deferred, "rage/deferred/deferred"
133138
end
134139

135140
module RageController

lib/rage/code_loader.rb

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ def setup
2222
@loader.enable_reloading if enable_reloading
2323
@loader.setup
2424
@loader.eager_load if enable_eager_loading
25+
26+
configure_components
2527
end
2628

2729
# in standalone mode - reload the code and the routes
@@ -34,13 +36,7 @@ def reload
3436
Rage.__router.reset_routes
3537
load("#{Rage.root}/config/routes.rb")
3638

37-
unless Rage.autoload?(:Cable) # the `Cable` component is loaded
38-
Rage::Cable.__router.reset
39-
end
40-
41-
unless Rage.autoload?(:OpenAPI) # the `OpenAPI` component is loaded
42-
Rage::OpenAPI.__reset_data_cache
43-
end
39+
reload_components
4440
end
4541

4642
# in Rails mode - reset the routes; everything else will be done by Rails
@@ -50,13 +46,7 @@ def rails_mode_reload
5046
@reloading = true
5147
Rage.__router.reset_routes
5248

53-
unless Rage.autoload?(:Cable) # the `Cable` component is loaded
54-
Rage::Cable.__router.reset
55-
end
56-
57-
unless Rage.autoload?(:OpenAPI) # the `OpenAPI` component is loaded
58-
Rage::OpenAPI.__reset_data_cache
59-
end
49+
reload_components
6050
end
6151

6252
def reloading?
@@ -73,4 +63,25 @@ def check_updated!
7363
ensure
7464
@last_watched, @last_update_at = current_watched, current_update_at
7565
end
66+
67+
private
68+
69+
def configure_components
70+
if Rage.env.development? && (Rage.config.deferred.configured? || Rage.config.deferred.has_default_disk_storage?)
71+
# if there's at least one task, `Rage::Deferred` will be automatically loaded in production;
72+
# in development, however, eager loading is disabled, and we want to automatically load
73+
# the module in case it was explicitly configured or if a disk storage exists
74+
Rage::Deferred
75+
end
76+
end
77+
78+
def reload_components
79+
unless Rage.autoload?(:Cable) # the `Cable` component is loaded
80+
Rage::Cable.__router.reset
81+
end
82+
83+
unless Rage.autoload?(:OpenAPI) # the `OpenAPI` component is loaded
84+
Rage::OpenAPI.__reset_data_cache
85+
end
86+
end
7687
end

lib/rage/configuration.rb

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,20 @@
145145
# end
146146
# > ```
147147
#
148+
# # Deferred Configuration
149+
# • _config.deferred.backend_
150+
#
151+
# > Specifies the backend for deferred tasks. Supported values are `:disk`, which uses disk storage, or `nil`, which disables persistence of deferred tasks.
152+
# > The `:disk` backend accepts the following options:
153+
# >
154+
# > - `:path` - the path to the directory where deferred tasks will be stored. Defaults to `storage`.
155+
# > - `:prefix` - the prefix for the deferred task files. Defaults to `deferred-`.
156+
# > - `:fsync_frequency` - the frequency of `fsync` calls in seconds. Defaults to `0.5`.
157+
#
158+
# > ```ruby
159+
# config.deferred.backend = :disk, { path: "storage" }
160+
# > ```
161+
#
148162
# # Transient Settings
149163
#
150164
# The settings described in this section should be configured using **environment variables** and are either temporary or will become the default in the future.
@@ -208,6 +222,10 @@ def openapi
208222
@openapi ||= OpenAPI.new
209223
end
210224

225+
def deferred
226+
@deferred ||= Deferred.new
227+
end
228+
211229
def internal
212230
@internal ||= Internal.new
213231
end
@@ -347,6 +365,85 @@ class OpenAPI
347365
attr_accessor :tag_resolver
348366
end
349367

368+
class Deferred
369+
def initialize
370+
@backend_class = Rage::Deferred::Backends::Disk
371+
@backend_options = parse_disk_backend_options({})
372+
373+
@configured = false
374+
end
375+
376+
def backend
377+
@backend_class.new(**@backend_options)
378+
end
379+
380+
def backend=(config)
381+
@configured = true
382+
383+
backend_id, opts = if config.is_a?(Array)
384+
[config[0], config[1]]
385+
else
386+
[config, {}]
387+
end
388+
389+
@backend_class = case backend_id
390+
when :disk
391+
@backend_options = parse_disk_backend_options(opts)
392+
Rage::Deferred::Backends::Disk
393+
when nil
394+
Rage::Deferred::Backends::Nil
395+
else
396+
raise ArgumentError, "unsupported backend value; supported values are `:disk` and `nil`"
397+
end
398+
end
399+
400+
def default_disk_storage_path
401+
Pathname.new("storage")
402+
end
403+
404+
def default_disk_storage_prefix
405+
"deferred-"
406+
end
407+
408+
def has_default_disk_storage?
409+
default_disk_storage_path.glob("#{default_disk_storage_prefix}*").any?
410+
end
411+
412+
def configured?
413+
@configured
414+
end
415+
416+
private
417+
418+
def parse_disk_backend_options(opts)
419+
if opts.except(:path, :prefix, :fsync_frequency).any?
420+
raise ArgumentError, "unsupported backend options; supported values are `:path`, `:prefix`, `:fsync_frequency`"
421+
end
422+
423+
parsed_options = {}
424+
425+
parsed_options[:path] = if opts[:path]
426+
opts[:path].is_a?(Pathname) ? opts[:path] : Pathname.new(opts[:path])
427+
else
428+
default_disk_storage_path
429+
end
430+
431+
parsed_options[:prefix] = if opts[:prefix]
432+
opts[:prefix].end_with?("-") ? opts[:prefix] : "#{opts[:prefix]}-"
433+
else
434+
default_disk_storage_prefix
435+
end
436+
437+
parsed_options[:fsync_frequency] = if opts[:fsync_frequency]
438+
(opts[:fsync_frequency].to_i * 1_000).round
439+
else
440+
500
441+
end
442+
443+
parsed_options
444+
end
445+
end
446+
350447
# @private
351448
class Internal
352449
attr_accessor :rails_mode

0 commit comments

Comments
 (0)