mission_control-jobs 0.1.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -10
  3. data/app/controllers/concerns/mission_control/jobs/adapter_features.rb +10 -6
  4. data/app/controllers/concerns/mission_control/jobs/failed_jobs_bulk_operations.rb +1 -1
  5. data/app/controllers/concerns/mission_control/jobs/not_found_redirections.rb +9 -1
  6. data/app/controllers/concerns/mission_control/jobs/queue_scoped.rb +1 -1
  7. data/app/controllers/mission_control/jobs/bulk_discards_controller.rb +1 -1
  8. data/app/controllers/mission_control/jobs/discards_controller.rb +1 -1
  9. data/app/controllers/mission_control/jobs/dispatches_controller.rb +13 -0
  10. data/app/controllers/mission_control/jobs/jobs_controller.rb +3 -3
  11. data/app/controllers/mission_control/jobs/queues_controller.rb +4 -4
  12. data/app/controllers/mission_control/jobs/recurring_tasks_controller.rb +23 -0
  13. data/app/controllers/mission_control/jobs/retries_controller.rb +1 -1
  14. data/app/controllers/mission_control/jobs/workers_controller.rb +6 -1
  15. data/app/helpers/mission_control/jobs/jobs_helper.rb +6 -2
  16. data/app/helpers/mission_control/jobs/navigation_helper.rb +2 -1
  17. data/app/models/mission_control/jobs/page.rb +8 -8
  18. data/app/models/mission_control/jobs/recurring_task.rb +17 -0
  19. data/app/views/layouts/mission_control/jobs/_application_selection.html.erb +1 -1
  20. data/app/views/layouts/mission_control/jobs/application.html.erb +1 -0
  21. data/app/views/mission_control/jobs/jobs/_error_information.html.erb +0 -1
  22. data/app/views/mission_control/jobs/jobs/_general_information.html.erb +1 -1
  23. data/app/views/mission_control/jobs/jobs/_jobs_page.html.erb +8 -10
  24. data/app/views/mission_control/jobs/jobs/_title.html.erb +3 -0
  25. data/app/views/mission_control/jobs/jobs/blocked/_actions.html.erb +3 -0
  26. data/app/views/mission_control/jobs/jobs/blocked/_job.html.erb +3 -0
  27. data/app/views/mission_control/jobs/jobs/index.html.erb +2 -2
  28. data/app/views/mission_control/jobs/jobs/scheduled/_actions.html.erb +4 -0
  29. data/app/views/mission_control/jobs/jobs/scheduled/_job.html.erb +4 -1
  30. data/app/views/mission_control/jobs/queues/_queue_title.html.erb +1 -1
  31. data/app/views/mission_control/jobs/queues/show.html.erb +2 -2
  32. data/app/views/mission_control/jobs/recurring_tasks/_general_information.html.erb +16 -0
  33. data/app/views/mission_control/jobs/recurring_tasks/_recurring_task.html.erb +14 -0
  34. data/app/views/mission_control/jobs/recurring_tasks/_title.html.erb +7 -0
  35. data/app/views/mission_control/jobs/recurring_tasks/index.html.erb +16 -0
  36. data/app/views/mission_control/jobs/recurring_tasks/show.html.erb +14 -0
  37. data/app/views/mission_control/jobs/{workers → shared}/_job.html.erb +9 -1
  38. data/app/views/mission_control/jobs/shared/_jobs.html.erb +14 -0
  39. data/app/views/mission_control/jobs/shared/_pagination_toolbar.html.erb +3 -3
  40. data/app/views/mission_control/jobs/workers/_workers_page.html.erb +15 -0
  41. data/app/views/mission_control/jobs/workers/index.html.erb +2 -13
  42. data/app/views/mission_control/jobs/workers/show.html.erb +9 -2
  43. data/config/routes.rb +2 -2
  44. data/lib/active_job/executing.rb +3 -6
  45. data/lib/active_job/failed.rb +0 -4
  46. data/lib/active_job/job_proxy.rb +6 -0
  47. data/lib/active_job/jobs_relation.rb +17 -6
  48. data/lib/active_job/queue_adapters/resque_ext.rb +2 -2
  49. data/lib/active_job/queue_adapters/solid_queue_ext/recurring_tasks.rb +43 -0
  50. data/lib/active_job/queue_adapters/solid_queue_ext/workers.rb +41 -0
  51. data/lib/active_job/queue_adapters/solid_queue_ext.rb +51 -55
  52. data/lib/mission_control/jobs/adapter.rb +67 -19
  53. data/lib/mission_control/jobs/console/helpers.rb +1 -1
  54. data/lib/mission_control/jobs/engine.rb +14 -3
  55. data/lib/mission_control/jobs/server/recurring_tasks.rb +15 -0
  56. data/lib/mission_control/jobs/server/serializable.rb +1 -1
  57. data/lib/mission_control/jobs/server/workers.rb +3 -5
  58. data/lib/mission_control/jobs/server.rb +1 -1
  59. data/lib/mission_control/jobs/version.rb +1 -1
  60. data/lib/mission_control/jobs/workers_relation.rb +78 -0
  61. data/lib/mission_control/jobs.rb +4 -0
  62. metadata +66 -11
  63. data/app/jobs/mission_control/jobs/application_job.rb +0 -6
  64. data/app/mailers/mission_control/jobs/application_mailer.rb +0 -8
  65. data/app/views/mission_control/jobs/workers/_jobs.html.erb +0 -20
@@ -3,17 +3,21 @@ module MissionControl::Jobs::Adapter
3
3
  block.call
4
4
  end
5
5
 
6
- def supported_statuses
6
+ def supports_job_status?(status)
7
+ supported_job_statuses.include?(status)
8
+ end
9
+
10
+ def supported_job_statuses
7
11
  # All adapters need to support these at a minimum
8
12
  [ :pending, :failed ]
9
13
  end
10
14
 
11
- def supports_filter?(jobs_relation, filter)
12
- supported_filters(jobs_relation).include?(filter)
15
+ def supports_job_filter?(jobs_relation, filter)
16
+ supported_job_filters(jobs_relation).include?(filter)
13
17
  end
14
18
 
15
19
  # List of filters supported natively. Non-supported filters are done in memory.
16
- def supported_filters(jobs_relation)
20
+ def supported_job_filters(jobs_relation)
17
21
  []
18
22
  end
19
23
 
@@ -25,11 +29,38 @@ module MissionControl::Jobs::Adapter
25
29
  false
26
30
  end
27
31
 
32
+ def supports_recurring_tasks?
33
+ false
34
+ end
35
+
36
+ # Returns an array with the list of recurring tasks. Each task is represented as a hash
37
+ # with these attributes:
38
+ # {
39
+ # id: "periodic-job",
40
+ # job_class_name: "MyJob",
41
+ # arguments: [ 123, { arg: :value }]
42
+ # schedule: "every monday at 9 am",
43
+ # last_enqueued_at: Fri, 26 Jan 2024 20:31:09.652174000 UTC +00:00,
44
+ # }
45
+ def recurring_tasks
46
+ if supports_recurring_tasks?
47
+ raise_incompatible_adapter_error_from :recurring_tasks
48
+ end
49
+ end
50
+
51
+ # Returns a recurring task represented by a hash as indicated above
52
+ def find_recurring_task(recurring_task_id)
53
+ if supports_recurring_tasks?
54
+ raise_incompatible_adapter_error_from :find_recurring_task
55
+ end
56
+ end
57
+
58
+
28
59
  # Returns an array with the list of workers. Each worker is represented as a hash
29
60
  # with these attributes:
30
61
  # {
31
62
  # id: 123,
32
- # name: "adapter-name",
63
+ # name: "worker-name",
33
64
  # hostname: "hey-default-101",
34
65
  # last_heartbeat_at: Fri, 26 Jan 2024 20:31:09.652174000 UTC +00:00,
35
66
  # configuration: { ... }
@@ -37,10 +68,18 @@ module MissionControl::Jobs::Adapter
37
68
  # }
38
69
  def workers
39
70
  if exposes_workers?
40
- raise MissionControl::Jobs::Errors::IncompatibleAdapter("Adapter must implement `workers`")
71
+ raise_incompatible_adapter_error_from :workers
72
+ end
73
+ end
74
+
75
+ # Returns a worker represented by a hash as indicated above
76
+ def find_worker(worker_id)
77
+ if exposes_workers?
78
+ raise_incompatible_adapter_error_from :find_worker
41
79
  end
42
80
  end
43
81
 
82
+
44
83
  # Returns an array with the list of queues. Each queue is represented as a hash
45
84
  # with these attributes:
46
85
  # {
@@ -49,60 +88,69 @@ module MissionControl::Jobs::Adapter
49
88
  # active: true
50
89
  # }
51
90
  def queues
52
- raise MissionControl::Jobs::Errors::IncompatibleAdapter("Adapter must implement `queue_names`")
91
+ raise_incompatible_adapter_error_from :queue_names
53
92
  end
54
93
 
55
94
  def queue_size(queue_name)
56
- raise MissionControl::Jobs::Errors::IncompatibleAdapter("Adapter must implement `queue_size`")
95
+ raise_incompatible_adapter_error_from :queue_size
57
96
  end
58
97
 
59
98
  def clear_queue(queue_name)
60
- raise MissionControl::Jobs::Errors::IncompatibleAdapter("Adapter must implement `clear_queue`")
99
+ raise_incompatible_adapter_error_from :clear_queue
61
100
  end
62
101
 
63
102
  def pause_queue(queue_name)
64
103
  if supports_queue_pausing?
65
- raise MissionControl::Jobs::Errors::IncompatibleAdapter("Adapter must implement `pause_queue`")
104
+ raise_incompatible_adapter_error_from :pause_queue
66
105
  end
67
106
  end
68
107
 
69
108
  def resume_queue(queue_name)
70
109
  if supports_queue_pausing?
71
- raise MissionControl::Jobs::Errors::IncompatibleAdapter("Adapter must implement `resume_queue`")
110
+ raise_incompatible_adapter_error_from :resume_queue
72
111
  end
73
112
  end
74
113
 
75
114
  def queue_paused?(queue_name)
76
115
  if supports_queue_pausing?
77
- raise MissionControl::Jobs::Errors::IncompatibleAdapter("Adapter must implement `queue_paused?`")
116
+ raise_incompatible_adapter_error_from :queue_paused?
78
117
  end
79
118
  end
80
119
 
81
120
  def jobs_count(jobs_relation)
82
- raise MissionControl::Jobs::Errors::IncompatibleAdapter("Adapter must implement `jobs_count`")
121
+ raise_incompatible_adapter_error_from :jobs_count
83
122
  end
84
123
 
85
124
  def fetch_jobs(jobs_relation)
86
- raise MissionControl::Jobs::Errors::IncompatibleAdapter("Adapter must implement `fetch_jobs`")
125
+ raise_incompatible_adapter_error_from :fetch_jobs
87
126
  end
88
127
 
89
128
  def retry_all_jobs(jobs_relation)
90
- raise MissionControl::Jobs::Errors::IncompatibleAdapter("Adapter must implement `retry_all_jobs`")
129
+ raise_incompatible_adapter_error_from :retry_all_jobs
91
130
  end
92
131
 
93
132
  def retry_job(job, jobs_relation)
94
- raise MissionControl::Jobs::Errors::IncompatibleAdapter("Adapter must implement `retry_job`")
133
+ raise_incompatible_adapter_error_from :retry_job
95
134
  end
96
135
 
97
136
  def discard_all_jobs(jobs_relation)
98
- raise MissionControl::Jobs::Errors::IncompatibleAdapter("Adapter must implement `discard_all_jobs`")
137
+ raise_incompatible_adapter_error_from :discard_all_jobs
99
138
  end
100
139
 
101
140
  def discard_job(job, jobs_relation)
102
- raise MissionControl::Jobs::Errors::IncompatibleAdapter("Adapter must implement `discard_job`")
141
+ raise_incompatible_adapter_error_from :discard_job
142
+ end
143
+
144
+ def dispatch_job(job, jobs_relation)
145
+ raise_incompatible_adapter_error_from :dispatch_job
103
146
  end
104
147
 
105
148
  def find_job(job_id, *)
106
- raise MissionControl::Jobs::Errors::IncompatibleAdapter("Adapter must implement `find_job`")
149
+ raise_incompatible_adapter_error_from :find_job
107
150
  end
151
+
152
+ private
153
+ def raise_incompatible_adapter_error_from(method_name)
154
+ raise MissionControl::Jobs::Errors::IncompatibleAdapter, "Adapter #{ActiveJob.adapter_name(self)} must implement `#{method_name}`"
155
+ end
108
156
  end
@@ -11,7 +11,7 @@ module MissionControl::Jobs::Console::Helpers
11
11
  puts "You are currently connected to #{MissionControl::Jobs::Current.server}" if MissionControl::Jobs::Current.server
12
12
 
13
13
  puts "You can connect to a job server with"
14
- puts " connect_to <app_id>:<server_id>\n\n"
14
+ puts %( connect_to "<app_id>:<server_id>"\n\n)
15
15
 
16
16
  puts "Available job servers:\n"
17
17
 
@@ -20,8 +20,8 @@ module MissionControl
20
20
  MissionControl::Jobs.public_send("#{key}=", value)
21
21
  end
22
22
 
23
- if config.active_job.queue_adapter.present? && MissionControl::Jobs.adapters.empty?
24
- MissionControl::Jobs.adapters << config.active_job.queue_adapter
23
+ if MissionControl::Jobs.adapters.empty?
24
+ MissionControl::Jobs.adapters << (config.active_job.queue_adapter || :async)
25
25
  end
26
26
  end
27
27
 
@@ -36,6 +36,7 @@ module MissionControl
36
36
 
37
37
  config.before_initialize do
38
38
  if MissionControl::Jobs.adapters.include?(:resque)
39
+ require "resque/thread_safe_redis"
39
40
  ActiveJob::QueueAdapters::ResqueAdapter.prepend ActiveJob::QueueAdapters::ResqueExt
40
41
  Resque.prepend Resque::ThreadSafeRedis
41
42
  end
@@ -43,6 +44,8 @@ module MissionControl
43
44
  if MissionControl::Jobs.adapters.include?(:solid_queue)
44
45
  ActiveJob::QueueAdapters::SolidQueueAdapter.prepend ActiveJob::QueueAdapters::SolidQueueExt
45
46
  end
47
+
48
+ ActiveJob::QueueAdapters::AsyncAdapter.include MissionControl::Jobs::Adapter
46
49
  end
47
50
 
48
51
  config.after_initialize do |app|
@@ -63,6 +66,7 @@ module MissionControl
63
66
  end
64
67
 
65
68
  console do
69
+ require "irb"
66
70
  require "irb/context"
67
71
 
68
72
  IRB::Context.prepend(MissionControl::Jobs::Console::Context)
@@ -71,7 +75,14 @@ module MissionControl
71
75
  MissionControl::Jobs.delay_between_bulk_operation_batches = 2
72
76
  MissionControl::Jobs.logger = ActiveSupport::Logger.new(STDOUT)
73
77
 
74
- puts "\n\nType 'jobs_help' to see how to connect to the available job servers to manage jobs\n\n"
78
+ if MissionControl::Jobs.applications.one? && (application = MissionControl::Jobs.applications.first) && application.servers.one?
79
+ MissionControl::Jobs::Current.application = application
80
+ MissionControl::Jobs::Current.server = application.servers.first
81
+ end
82
+
83
+ if MissionControl::Jobs.show_console_help
84
+ puts "\n\nType 'jobs_help' to see how to connect to the available job servers to manage jobs\n\n"
85
+ end
75
86
  end
76
87
 
77
88
  initializer "mission_control-jobs.assets" do |app|
@@ -0,0 +1,15 @@
1
+ module MissionControl::Jobs::Server::RecurringTasks
2
+ def recurring_tasks
3
+ queue_adapter.recurring_tasks.collect do |task|
4
+ MissionControl::Jobs::RecurringTask.new(queue_adapter: queue_adapter, **task)
5
+ end.sort_by(&:id)
6
+ end
7
+
8
+ def find_recurring_task(task_id)
9
+ if task = queue_adapter.find_recurring_task(task_id)
10
+ MissionControl::Jobs::RecurringTask.new(queue_adapter: queue_adapter, **task)
11
+ else
12
+ raise MissionControl::Jobs::Errors::ResourceNotFound, "Recurring task with id '#{task_id}' not found"
13
+ end
14
+ end
15
+ end
@@ -18,7 +18,7 @@ module MissionControl::Jobs::Server::Serializable
18
18
  end
19
19
 
20
20
  def to_global_id
21
- suffix = ":#{id}" if application.servers.length > 1
21
+ suffix = ":#{id}" if application.servers.many?
22
22
  "#{application&.id}#{suffix}"
23
23
  end
24
24
  end
@@ -1,15 +1,13 @@
1
1
  module MissionControl::Jobs::Server::Workers
2
- def workers
3
- queue_adapter.workers.collect do |worker|
4
- MissionControl::Jobs::Worker.new(queue_adapter: queue_adapter, **worker)
5
- end
2
+ def workers_relation
3
+ MissionControl::Jobs::WorkersRelation.new(queue_adapter: queue_adapter)
6
4
  end
7
5
 
8
6
  def find_worker(worker_id)
9
7
  if worker = queue_adapter.find_worker(worker_id)
10
8
  MissionControl::Jobs::Worker.new(queue_adapter: queue_adapter, **worker)
11
9
  else
12
- raise MissionControl::Jobs::Errors::ResourceNotFound, "No worker found with ID #{worker_id}"
10
+ raise MissionControl::Jobs::Errors::ResourceNotFound, "Worker with id '#{worker_id}' not found"
13
11
  end
14
12
  end
15
13
  end
@@ -2,7 +2,7 @@ require "active_job/queue_adapter"
2
2
 
3
3
  class MissionControl::Jobs::Server
4
4
  include MissionControl::Jobs::IdentifiedByName
5
- include Serializable, Workers
5
+ include Serializable, RecurringTasks, Workers
6
6
 
7
7
  attr_reader :name, :queue_adapter, :application
8
8
 
@@ -1,5 +1,5 @@
1
1
  module MissionControl
2
2
  module Jobs
3
- VERSION = "0.1.1"
3
+ VERSION = "0.2.1"
4
4
  end
5
5
  end
@@ -0,0 +1,78 @@
1
+ # A relation of workers.
2
+ #
3
+ # Relations are enumerable, so you can use +Enumerable+ methods on them.
4
+ # Notice however that using these methods will imply loading all the relation
5
+ # in memory, which could introduce performance concerns.
6
+ class MissionControl::Jobs::WorkersRelation
7
+ include Enumerable
8
+
9
+ attr_accessor :offset_value, :limit_value
10
+
11
+ delegate :last, :[], :to_s, :reverse, to: :to_a
12
+
13
+ ALL_WORKERS_LIMIT = 100_000_000 # When no limit value it defaults to "all workers"
14
+
15
+ def initialize(queue_adapter:)
16
+ @queue_adapter = queue_adapter
17
+
18
+ set_defaults
19
+ end
20
+
21
+ def offset(offset)
22
+ clone_with offset_value: offset
23
+ end
24
+
25
+ def limit(limit)
26
+ clone_with limit_value: limit
27
+ end
28
+
29
+ def each(&block)
30
+ workers.each(&block)
31
+ end
32
+
33
+ def reload
34
+ @count = @workers = nil
35
+ self
36
+ end
37
+
38
+ def count
39
+ if loaded?
40
+ to_a.length
41
+ else
42
+ query_count
43
+ end
44
+ end
45
+
46
+ def empty?
47
+ count == 0
48
+ end
49
+
50
+ alias length count
51
+ alias size count
52
+
53
+ private
54
+ def set_defaults
55
+ self.offset_value = 0
56
+ self.limit_value = ALL_WORKERS_LIMIT
57
+ end
58
+
59
+ def workers
60
+ @workers ||= @queue_adapter.fetch_workers(self)
61
+ end
62
+
63
+ def query_count
64
+ @count ||= @queue_adapter.count_workers(self)
65
+ end
66
+
67
+ def loaded?
68
+ !@workers.nil?
69
+ end
70
+
71
+ def clone_with(**properties)
72
+ dup.reload.tap do |relation|
73
+ properties.each do |key, value|
74
+ relation.send("#{key}=", value)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -6,6 +6,7 @@ require "zeitwerk"
6
6
  loader = Zeitwerk::Loader.new
7
7
  loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
8
8
  loader.push_dir(File.expand_path("..", __dir__))
9
+ loader.ignore("#{File.expand_path("..", __dir__)}/resque")
9
10
  loader.setup
10
11
 
11
12
  module MissionControl
@@ -15,5 +16,8 @@ module MissionControl
15
16
  mattr_accessor :base_controller_class, default: "::ApplicationController"
16
17
  mattr_accessor :delay_between_bulk_operation_batches, default: 0
17
18
  mattr_accessor :logger, default: ActiveSupport::Logger.new(nil)
19
+ mattr_accessor :internal_query_count_limit, default: 500_000 # Hard limit to keep unlimited count queries fast enough
20
+ mattr_accessor :show_console_help, default: true
21
+ mattr_accessor :scheduled_job_delay_threshold, default: 1.minute
18
22
  end
19
23
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mission_control-jobs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jorge Manrubia
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-01-31 00:00:00.000000000 Z
11
+ date: 2024-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -154,16 +154,16 @@ dependencies:
154
154
  name: redis
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
- - - "~>"
157
+ - - ">="
158
158
  - !ruby/object:Gem::Version
159
- version: 4.0.0
159
+ version: '0'
160
160
  type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
- - - "~>"
164
+ - - ">="
165
165
  - !ruby/object:Gem::Version
166
- version: 4.0.0
166
+ version: '0'
167
167
  - !ruby/object:Gem::Dependency
168
168
  name: redis-namespace
169
169
  requirement: !ruby/object:Gem::Requirement
@@ -207,7 +207,49 @@ dependencies:
207
207
  - !ruby/object:Gem::Version
208
208
  version: '0'
209
209
  - !ruby/object:Gem::Dependency
210
- name: rubocop-rails
210
+ name: rubocop-rails-omakase
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
223
+ - !ruby/object:Gem::Dependency
224
+ name: sprockets-rails
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: '0'
237
+ - !ruby/object:Gem::Dependency
238
+ name: sqlite3
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: '0'
244
+ type: :development
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
251
+ - !ruby/object:Gem::Dependency
252
+ name: puma
211
253
  requirement: !ruby/object:Gem::Requirement
212
254
  requirements:
213
255
  - - ">="
@@ -245,9 +287,11 @@ files:
245
287
  - app/controllers/mission_control/jobs/bulk_discards_controller.rb
246
288
  - app/controllers/mission_control/jobs/bulk_retries_controller.rb
247
289
  - app/controllers/mission_control/jobs/discards_controller.rb
290
+ - app/controllers/mission_control/jobs/dispatches_controller.rb
248
291
  - app/controllers/mission_control/jobs/jobs_controller.rb
249
292
  - app/controllers/mission_control/jobs/queues/pauses_controller.rb
250
293
  - app/controllers/mission_control/jobs/queues_controller.rb
294
+ - app/controllers/mission_control/jobs/recurring_tasks_controller.rb
251
295
  - app/controllers/mission_control/jobs/retries_controller.rb
252
296
  - app/controllers/mission_control/jobs/workers_controller.rb
253
297
  - app/helpers/mission_control/jobs/application_helper.rb
@@ -261,11 +305,10 @@ files:
261
305
  - app/javascript/mission_control/jobs/controllers/index.js
262
306
  - app/javascript/mission_control/jobs/helpers/debounce_helpers.js
263
307
  - app/javascript/mission_control/jobs/helpers/index.js
264
- - app/jobs/mission_control/jobs/application_job.rb
265
- - app/mailers/mission_control/jobs/application_mailer.rb
266
308
  - app/models/mission_control/jobs/application_record.rb
267
309
  - app/models/mission_control/jobs/current.rb
268
310
  - app/models/mission_control/jobs/page.rb
311
+ - app/models/mission_control/jobs/recurring_task.rb
269
312
  - app/models/mission_control/jobs/worker.rb
270
313
  - app/views/layouts/mission_control/jobs/_application_selection.html.erb
271
314
  - app/views/layouts/mission_control/jobs/_flash.html.erb
@@ -281,12 +324,14 @@ files:
281
324
  - app/views/mission_control/jobs/jobs/_raw_data.html.erb
282
325
  - app/views/mission_control/jobs/jobs/_title.html.erb
283
326
  - app/views/mission_control/jobs/jobs/_toolbar.html.erb
327
+ - app/views/mission_control/jobs/jobs/blocked/_actions.html.erb
284
328
  - app/views/mission_control/jobs/jobs/blocked/_job.html.erb
285
329
  - app/views/mission_control/jobs/jobs/failed/_actions.html.erb
286
330
  - app/views/mission_control/jobs/jobs/failed/_job.html.erb
287
331
  - app/views/mission_control/jobs/jobs/finished/_job.html.erb
288
332
  - app/views/mission_control/jobs/jobs/in_progress/_job.html.erb
289
333
  - app/views/mission_control/jobs/jobs/index.html.erb
334
+ - app/views/mission_control/jobs/jobs/scheduled/_actions.html.erb
290
335
  - app/views/mission_control/jobs/jobs/scheduled/_job.html.erb
291
336
  - app/views/mission_control/jobs/jobs/show.html.erb
292
337
  - app/views/mission_control/jobs/queues/_actions.html.erb
@@ -295,13 +340,19 @@ files:
295
340
  - app/views/mission_control/jobs/queues/_queue_title.html.erb
296
341
  - app/views/mission_control/jobs/queues/index.html.erb
297
342
  - app/views/mission_control/jobs/queues/show.html.erb
343
+ - app/views/mission_control/jobs/recurring_tasks/_general_information.html.erb
344
+ - app/views/mission_control/jobs/recurring_tasks/_recurring_task.html.erb
345
+ - app/views/mission_control/jobs/recurring_tasks/_title.html.erb
346
+ - app/views/mission_control/jobs/recurring_tasks/index.html.erb
347
+ - app/views/mission_control/jobs/recurring_tasks/show.html.erb
348
+ - app/views/mission_control/jobs/shared/_job.html.erb
349
+ - app/views/mission_control/jobs/shared/_jobs.html.erb
298
350
  - app/views/mission_control/jobs/shared/_pagination_toolbar.html.erb
299
351
  - app/views/mission_control/jobs/workers/_configuration.html.erb
300
- - app/views/mission_control/jobs/workers/_job.html.erb
301
- - app/views/mission_control/jobs/workers/_jobs.html.erb
302
352
  - app/views/mission_control/jobs/workers/_raw_data.html.erb
303
353
  - app/views/mission_control/jobs/workers/_title.html.erb
304
354
  - app/views/mission_control/jobs/workers/_worker.html.erb
355
+ - app/views/mission_control/jobs/workers/_workers_page.html.erb
305
356
  - app/views/mission_control/jobs/workers/index.html.erb
306
357
  - app/views/mission_control/jobs/workers/show.html.erb
307
358
  - config/importmap.rb
@@ -318,6 +369,8 @@ files:
318
369
  - lib/active_job/queue.rb
319
370
  - lib/active_job/queue_adapters/resque_ext.rb
320
371
  - lib/active_job/queue_adapters/solid_queue_ext.rb
372
+ - lib/active_job/queue_adapters/solid_queue_ext/recurring_tasks.rb
373
+ - lib/active_job/queue_adapters/solid_queue_ext/workers.rb
321
374
  - lib/active_job/queues.rb
322
375
  - lib/mission_control/jobs.rb
323
376
  - lib/mission_control/jobs/adapter.rb
@@ -331,9 +384,11 @@ files:
331
384
  - lib/mission_control/jobs/identified_by_name.rb
332
385
  - lib/mission_control/jobs/identified_elements.rb
333
386
  - lib/mission_control/jobs/server.rb
387
+ - lib/mission_control/jobs/server/recurring_tasks.rb
334
388
  - lib/mission_control/jobs/server/serializable.rb
335
389
  - lib/mission_control/jobs/server/workers.rb
336
390
  - lib/mission_control/jobs/version.rb
391
+ - lib/mission_control/jobs/workers_relation.rb
337
392
  - lib/resque/thread_safe_redis.rb
338
393
  - lib/tasks/mission_control/jobs_tasks.rake
339
394
  homepage: https://github.com/basecamp/mission_control-jobs
@@ -1,6 +0,0 @@
1
- module MissionControl
2
- module Jobs
3
- class ApplicationJob < ActiveJob::Base
4
- end
5
- end
6
- end
@@ -1,8 +0,0 @@
1
- module MissionControl
2
- module Jobs
3
- class ApplicationMailer < ActionMailer::Base
4
- default from: "from@example.com"
5
- layout "mailer"
6
- end
7
- end
8
- end
@@ -1,20 +0,0 @@
1
- <% if @worker.jobs.empty? %>
2
- <%= blank_status_notice "This worker is idle" %>
3
- <% else %>
4
- <h2 class="subtitle">Running <%= worker.jobs.size %> jobs</h2>
5
-
6
- <table class="jobs table workers is-hoverable is-fullwidth">
7
- <tbody>
8
- <thead>
9
- <tr>
10
- <th style="width: 30%;">Job</th>
11
- <th></th>
12
- <th style="width: 15%;">Running for</th>
13
- </tr>
14
- </thead>
15
-
16
- <%= render partial: "mission_control/jobs/workers/job", collection: @worker.jobs %>
17
-
18
- </tbody>
19
- </table>
20
- <% end %>