sidekiq_adhoc_job 0.1.5 → 0.3.1

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: c0f35c0912b36fde038556110a6a116b789aaaf62cab80bd43521e1c50eec4ec
4
- data.tar.gz: 18913f33c03e1a976bafeac7fa03f575f87c43f6a325c00d92f9b22370014667
3
+ metadata.gz: 756b8b12f8763a43f6fdcf9608c244e7c6858cb05c7b342414377fb4f37184d3
4
+ data.tar.gz: 8ebbe33d96929bd6a50a5cd11a10cbd969a2d19aee72ca39e64cbca1e0a8e98c
5
5
  SHA512:
6
- metadata.gz: 1790167e58fe6b6cfe2ec654e00801b31249e04041463505130f4d0857162dd4b55f2234e3ea2fb1cba1ad0d54e2601ca8d640eff7bb4e2aac94bd33f9cf0845
7
- data.tar.gz: a7e0161b04b1cfbe0a7b0b7e9038f8c0802952925b33ed05ec3f356160d0ba2c9dd967f16e04bc4d9cfad70c178c31cd8311a61c434e60fc689a7cc1fc1fc76b
6
+ metadata.gz: eaaa17c4ef1866a26d479d24b8c7c0d7d1c26987a77aec481bf5541df9c1e65910e275f9728ec9cbc1058f05982ea9e3514bd9447a22a19034f6273badaf3e21
7
+ data.tar.gz: b1287b3d6205a94ef56cd4d4d7daf98dc00662b0fc40c22555678836131082cee76414d493760e52a3e395bc52130785988f38a215af00e19e0c2e7e8d74cc5c
@@ -3,6 +3,7 @@ require 'sidekiq/web'
3
3
 
4
4
  require 'sidekiq_adhoc_job/utils/string'
5
5
  require 'sidekiq_adhoc_job/utils/class_inspector'
6
+ require 'sidekiq_adhoc_job/strategy'
6
7
  require 'sidekiq_adhoc_job/worker_classes_loader'
7
8
  require 'sidekiq_adhoc_job/web/job_presenter'
8
9
  require 'sidekiq_adhoc_job/services/schedule_adhoc_job'
@@ -10,7 +11,13 @@ require 'sidekiq_adhoc_job/web'
10
11
 
11
12
  module SidekiqAdhocJob
12
13
 
13
- InvalidConfigurationError ||= Class.new(RuntimeError)
14
+ StringUtil ||= Utils::String
15
+
16
+ module Strategies
17
+ autoload :Default, 'sidekiq_adhoc_job/strategies/default'
18
+ autoload :ActiveJob, 'sidekiq_adhoc_job/strategies/active_job'
19
+ autoload :RailsApplicationJob, 'sidekiq_adhoc_job/strategies/rails_application_job'
20
+ end
14
21
 
15
22
  def self.configure
16
23
  @_config = Configuration.new
@@ -22,24 +29,39 @@ module SidekiqAdhocJob
22
29
  end
23
30
 
24
31
  def self.init
25
- raise InvalidConfigurationError, 'Must configure before init' unless @_config&.configured?
26
-
27
- SidekiqAdhocJob::WorkerClassesLoader.load(@_config.module_names)
32
+ SidekiqAdhocJob::WorkerClassesLoader.load(@_config.module_names, load_paths: @_config.load_paths, strategy: @_config.strategy)
28
33
 
29
34
  Sidekiq::Web.register(SidekiqAdhocJob::Web)
30
35
  Sidekiq::Web.tabs['adhoc_jobs'] = 'adhoc-jobs'
31
36
  Sidekiq::Web.locales << File.expand_path('sidekiq_adhoc_job/web/locales', __dir__)
32
37
  end
33
38
 
39
+ def self.strategies
40
+ @_strategies ||= []
41
+ end
42
+
34
43
  class Configuration
35
- attr_accessor :module_names
44
+ attr_accessor :load_paths, :module_names, :strategy_name
36
45
 
37
46
  def initialize
47
+ @load_paths = []
38
48
  @module_names = []
49
+ @strategy_name = :default
50
+ end
51
+
52
+ def module_names
53
+ Array(@module_names).map(&:to_s)
39
54
  end
40
55
 
41
- def configured?
42
- !@module_names.empty?
56
+ def strategy
57
+ @strategy ||= case strategy_name
58
+ when :default
59
+ SidekiqAdhocJob::Strategies::Default.new(module_names)
60
+ else
61
+ strategy_klass = SidekiqAdhocJob::Strategies.const_get(StringUtil.camelize(strategy_name.to_s).to_s)
62
+ raise InvalidConfigurationError, "Invalid strategy name" unless strategy_klass
63
+ strategy_klass.new(module_names)
64
+ end
43
65
  end
44
66
  end
45
67
 
@@ -16,7 +16,7 @@ module SidekiqAdhocJob
16
16
  end
17
17
 
18
18
  def call
19
- worker_klass.perform_async(*worker_params)
19
+ SidekiqAdhocJob.config.strategy.perform_async(worker_klass, *worker_params)
20
20
  end
21
21
 
22
22
  private
@@ -25,9 +25,11 @@ module SidekiqAdhocJob
25
25
  :allowed_params, :worker_params
26
26
 
27
27
  def parse_params
28
- @worker_params = allowed_params.map { |key| StringUtil.parse(request_params[key]) }
28
+ @worker_params = allowed_params
29
+ .reject { |key| request_params[key].empty? }
30
+ .map { |key| StringUtil.parse(request_params[key], symbolize: true) }
29
31
  if !!request_params[:rest_args] && !request_params[:rest_args].empty?
30
- @worker_params += request_params[:rest_args].split(',').map { |arg| StringUtil.parse(arg.strip) }
32
+ @worker_params << StringUtil.parse_json(request_params[:rest_args].strip, symbolize: true)
31
33
  end
32
34
  end
33
35
 
@@ -0,0 +1,19 @@
1
+ module SidekiqAdhocJob
2
+ module Strategies
3
+ class ActiveJob
4
+ include SidekiqAdhocJob::Strategy
5
+
6
+ def worker_class?(klass)
7
+ klass.superclass&.name == 'ActiveJob::Base'
8
+ end
9
+
10
+ def get_queue_name(klass_name)
11
+ klass_name.queue_name
12
+ end
13
+
14
+ def perform_async(klass, *params)
15
+ klass.perform_later(*params)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module SidekiqAdhocJob
2
+ module Strategies
3
+ class Default
4
+ include SidekiqAdhocJob::Strategy
5
+
6
+ def worker_class?(klass)
7
+ klass.included_modules.include?(Sidekiq::Worker)
8
+ end
9
+
10
+ def get_queue_name(klass_name)
11
+ klass_name.sidekiq_options['queue']
12
+ end
13
+
14
+ def perform_async(klass, *params)
15
+ klass.perform_async(*params)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module SidekiqAdhocJob
2
+ module Strategies
3
+ class RailsApplicationJob
4
+ include SidekiqAdhocJob::Strategy
5
+
6
+ def worker_class?(klass)
7
+ klass.superclass&.name == 'ApplicationJob'
8
+ end
9
+
10
+ def get_queue_name(klass_name)
11
+ klass_name.queue_name
12
+ end
13
+
14
+ def perform_async(klass, *params)
15
+ klass.perform_later(*params)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,43 @@
1
+ module SidekiqAdhocJob
2
+ module Strategy
3
+ def self.included(base)
4
+ SidekiqAdhocJob.strategies << base
5
+
6
+ base.extend ClassMethods
7
+ base.class_eval do
8
+ end
9
+ end
10
+
11
+ attr_reader :module_names, :worker_klasses
12
+
13
+ StringUtil ||= SidekiqAdhocJob::Utils::String
14
+
15
+ def initialize(module_names)
16
+ @module_names = module_names
17
+ @worker_klasses = {}
18
+ end
19
+
20
+ def load
21
+ ObjectSpace.each_object(Class).each do |klass|
22
+ next unless klass
23
+
24
+ if worker_class?(klass) && allowed_namespace?(klass.name, allowlist: module_names)
25
+ @worker_klasses[worker_path_name(klass.name)] = klass
26
+ end
27
+ end
28
+ end
29
+
30
+ def allowed_namespace?(class_name, allowlist:)
31
+ return true if allowlist.empty? || allowlist.include?('Module') # allow any namespace
32
+
33
+ allowlist.any? { |prefix| class_name.start_with?(prefix) }
34
+ end
35
+
36
+ def worker_path_name(worker_name)
37
+ Utils::String.underscore(worker_name).gsub('/', '_')
38
+ end
39
+
40
+ module ClassMethods
41
+ end
42
+ end
43
+ end
@@ -1,4 +1,5 @@
1
1
  # References: https://github.com/hanami/utils/blob/master/lib/hanami/utils/string.rb
2
+ # https://github.com/omniauth/omniauth/blob/cc0f5522621b4a372f4dff0aa608822aa082cb60/lib/omniauth.rb#L156
2
3
  module SidekiqAdhocJob
3
4
  module Utils
4
5
  class String
@@ -75,7 +76,15 @@ module SidekiqAdhocJob
75
76
  constant
76
77
  end
77
78
 
78
- def self.parse(input)
79
+ def self.camelize(word, first_letter_in_uppercase = true)
80
+ if first_letter_in_uppercase
81
+ word.to_s.gsub(%r{/(.?)}) { '::' + Regexp.last_match[1].upcase }.gsub(/(^|_)(.)/) { Regexp.last_match[2].upcase }
82
+ else
83
+ word.first + self.camelize(word)[1..-1]
84
+ end
85
+ end
86
+
87
+ def self.parse(input, symbolize: false)
79
88
  return unless input
80
89
 
81
90
  if input == 'true'
@@ -88,7 +97,7 @@ module SidekiqAdhocJob
88
97
  i
89
98
  elsif (f = parse_float(input))
90
99
  f
91
- elsif (j = parse_json(input))
100
+ elsif (j = parse_json(input, symbolize: symbolize))
92
101
  j
93
102
  else
94
103
  input
@@ -107,8 +116,8 @@ module SidekiqAdhocJob
107
116
  nil
108
117
  end
109
118
 
110
- def self.parse_json(input)
111
- JSON.parse(input)
119
+ def self.parse_json(input, symbolize: false)
120
+ JSON.parse(input, symbolize_names: symbolize)
112
121
  rescue JSON::ParserError => _e
113
122
  nil
114
123
  end
@@ -1,3 +1,3 @@
1
1
  module SidekiqAdhocJob
2
- VERSION = '0.1.5'.freeze
2
+ VERSION = '0.3.1'.freeze
3
3
  end
@@ -4,7 +4,7 @@ module SidekiqAdhocJob
4
4
  class JobPresenter
5
5
  include Sidekiq::WebHelpers
6
6
 
7
- attr_reader :name, :path_name, :queue, :has_rest_args, :args
7
+ attr_reader :name, :path_name, :queue, :required_args, :optional_args, :has_rest_args
8
8
 
9
9
  StringUtil ||= ::SidekiqAdhocJob::Utils::String
10
10
 
@@ -16,7 +16,6 @@ module SidekiqAdhocJob
16
16
  @required_args = args[:req] || []
17
17
  @optional_args = args[:opt] || []
18
18
  @has_rest_args = !!args[:rest]
19
- @args = @required_args + @optional_args
20
19
  end
21
20
 
22
21
  # Builds the presenter instances for the schedule hash
@@ -38,7 +37,7 @@ module SidekiqAdhocJob
38
37
  end
39
38
 
40
39
  def self.convert_klass_name_to_presenter(path_name, klass_name)
41
- queue = klass_name.sidekiq_options['queue']
40
+ queue = SidekiqAdhocJob.config.strategy.get_queue_name(klass_name)
42
41
  class_inspector = SidekiqAdhocJob::Utils::ClassInspector.new(klass_name)
43
42
  args = class_inspector.parameters(:perform)
44
43
  new(klass_name, path_name, queue, args)
@@ -1,7 +1,8 @@
1
1
  en:
2
2
  adhoc_jobs: Adhoc Jobs
3
3
  adhoc_jobs_actions: Actions
4
- adhoc_jobs_arguments: Required Arguments
4
+ adhoc_jobs_required_arguments: Required Arguments
5
+ adhoc_jobs_optional_arguments: Optional Arguments
5
6
  adhoc_jobs_go_back: Go Back
6
7
  adhoc_jobs_has_rest_arguments: Has Rest Arguments
7
8
  adhoc_jobs_name: Job Name
@@ -6,7 +6,8 @@
6
6
  <tr>
7
7
  <th><%= t('adhoc_jobs_name') %></th>
8
8
  <th><%= t('adhoc_jobs_queue') %></th>
9
- <th><%= t('adhoc_jobs_arguments') %></th>
9
+ <th><%= t('adhoc_jobs_required_arguments') %></th>
10
+ <th><%= t('adhoc_jobs_optional_arguments') %></th>
10
11
  <th><%= t('adhoc_jobs_has_rest_arguments') %></th>
11
12
  <th><%= t('adhoc_jobs_actions') %></th>
12
13
  </tr>
@@ -17,7 +18,8 @@
17
18
  <tr>
18
19
  <td><%= job.name %></td>
19
20
  <td><%= job.queue %></td>
20
- <td><%= job.args.join(', ') %></td>
21
+ <td><%= job.required_args.join(', ') %></td>
22
+ <td><%= job.optional_args.join(', ') %></td>
21
23
  <td><%= job.has_rest_args %></td>
22
24
  <td class="text-center">
23
25
  <a class="btn btn-warn btn-xs" href="<%= root_path %>adhoc-jobs/<%= URI.escape(job.path_name) %>">
@@ -1,11 +1,13 @@
1
1
  <h3><%= t('adhoc_jobs') %></h3>
2
2
 
3
+ <h4><%= SidekiqAdhocJob::Utils::String.classify(@presented_job.path_name) %></h4>
4
+
3
5
  <form method="POST" action="<%= root_path %>adhoc-jobs/<%= URI.escape(@presented_job.path_name) %>/schedule">
4
6
  <input type="hidden" name="authenticity_token" value="<%= @csrf_token %>" />
5
- <% if @presented_job.args.empty? && !@presented_job.has_rest_args %>
7
+ <% if @presented_job.required_args.empty? && @presented_job.optional_args.empty? && !@presented_job.has_rest_args %>
6
8
  <p>No job arguments</p>
7
9
  <% else %>
8
- <% @presented_job.args.each do |arg| %>
10
+ <% @presented_job.required_args.each do |arg| %>
9
11
  <div class="form-group row">
10
12
  <label class="col-sm-2 col-form-label" for="<%= arg %>">*<%= arg %>:</label>
11
13
  <div class="col-sm-4">
@@ -13,11 +15,19 @@
13
15
  </div>
14
16
  </div>
15
17
  <% end %>
18
+ <% @presented_job.optional_args.each do |arg| %>
19
+ <div class="form-group row">
20
+ <label class="col-sm-2 col-form-label" for="<%= arg %>"><%= arg %>:</label>
21
+ <div class="col-sm-4">
22
+ <input class="form-control" type="text" name="<%= arg %>" id="<%= arg %>"/>
23
+ </div>
24
+ </div>
25
+ <% end %>
16
26
  <% if @presented_job.has_rest_args %>
17
27
  <div class="form-group row">
18
- <label class="col-sm-2 col-form-label" for="rest_args">*Rest arguments (please separate each argument by comma):</label>
28
+ <label class="col-sm-2 col-form-label" for="rest_args">Rest arguments (please provide a json string representing the arguments):</label>
19
29
  <div class="col-sm-4">
20
- <input class="form-control" type="text" name="rest_args" id="rest_args" required/>
30
+ <input class="form-control" type="text" name="rest_args" id="rest_args"/>
21
31
  </div>
22
32
  </div>
23
33
  <% end %>
@@ -1,17 +1,11 @@
1
1
  module SidekiqAdhocJob
2
2
  class WorkerClassesLoader
3
-
4
- StringUtil ||= Utils::String
5
-
6
3
  @_worker_klasses = {}
7
4
 
8
- def self.load(module_names)
9
- module_consts = module_names.map { |name| StringUtil.constantize(name.to_s) }
10
- module_consts.each do |module_const|
11
- module_const.constants.each do |sub_module_const_sym|
12
- load_workers(module_const, sub_module_const_sym, @_worker_klasses)
13
- end
14
- end
5
+ def self.load(module_names, strategy:, load_paths:)
6
+ require_files(load_paths)
7
+ strategy.load
8
+ @_worker_klasses = strategy.worker_klasses
15
9
  end
16
10
 
17
11
  def self.worker_klasses
@@ -22,27 +16,8 @@ module SidekiqAdhocJob
22
16
  @_worker_klasses[path_name]
23
17
  end
24
18
 
25
- def self.load_workers(parent_module_const, module_sym, workers)
26
- qualified_name = module_sym.to_s
27
-
28
- module_const = begin
29
- StringUtil.constantize(qualified_name)
30
- rescue NameError => _e
31
- qualified_name = [parent_module_const, module_sym].compact.join('::')
32
- begin
33
- StringUtil.constantize(qualified_name)
34
- rescue NameError => _e
35
- nil
36
- end
37
- end
38
- return unless module_const && module_const.is_a?(Class)
39
-
40
- if module_const.include?(Sidekiq::Worker)
41
- path_name = StringUtil.underscore(qualified_name).gsub('/', '_')
42
- workers[path_name] = module_const
43
- return
44
- end
19
+ def self.require_files(load_paths)
20
+ Dir[File.join("", load_paths)].each { |path| require path } unless load_paths.empty?
45
21
  end
46
-
47
22
  end
48
23
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq_adhoc_job
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Goh Khoon Hiang
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-07-08 00:00:00.000000000 Z
11
+ date: 2020-12-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 2.0.1
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 2.0.1
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 3.8.0
61
+ version: 3.10.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 3.8.0
68
+ version: 3.10.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rack-test
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -86,28 +86,28 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 0.20.0
89
+ version: 0.26.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 0.20.0
96
+ version: 0.26.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: sidekiq
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - "~>"
101
+ - - "<"
102
102
  - !ruby/object:Gem::Version
103
- version: 5.2.7
103
+ version: '7'
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - "~>"
108
+ - - "<"
109
109
  - !ruby/object:Gem::Version
110
- version: 5.2.7
110
+ version: '7'
111
111
  description: Trigger jobs adhoc from Sidekiq web admin
112
112
  email:
113
113
  - gohkhoonhiang@gmail.com
@@ -117,6 +117,10 @@ extra_rdoc_files: []
117
117
  files:
118
118
  - lib/sidekiq_adhoc_job.rb
119
119
  - lib/sidekiq_adhoc_job/services/schedule_adhoc_job.rb
120
+ - lib/sidekiq_adhoc_job/strategies/active_job.rb
121
+ - lib/sidekiq_adhoc_job/strategies/default.rb
122
+ - lib/sidekiq_adhoc_job/strategies/rails_application_job.rb
123
+ - lib/sidekiq_adhoc_job/strategy.rb
120
124
  - lib/sidekiq_adhoc_job/utils/class_inspector.rb
121
125
  - lib/sidekiq_adhoc_job/utils/string.rb
122
126
  - lib/sidekiq_adhoc_job/version.rb
@@ -141,16 +145,16 @@ require_paths:
141
145
  - lib
142
146
  required_ruby_version: !ruby/object:Gem::Requirement
143
147
  requirements:
144
- - - ">="
148
+ - - "~>"
145
149
  - !ruby/object:Gem::Version
146
- version: 2.6.0
150
+ version: '2.6'
147
151
  required_rubygems_version: !ruby/object:Gem::Requirement
148
152
  requirements:
149
153
  - - ">="
150
154
  - !ruby/object:Gem::Version
151
155
  version: '0'
152
156
  requirements: []
153
- rubygems_version: 3.0.4
157
+ rubygems_version: 3.0.8
154
158
  signing_key:
155
159
  specification_version: 4
156
160
  summary: Trigger jobs adhoc from Sidekiq web admin