mission_control-jobs 0.4.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +15 -1
- data/app/assets/stylesheets/mission_control/jobs/bulma.min.css +3 -0
- data/app/assets/stylesheets/mission_control/jobs/jobs.css +1 -1
- data/app/controllers/mission_control/jobs/application_controller.rb +8 -0
- data/app/controllers/mission_control/jobs/discards_controller.rb +1 -1
- data/app/controllers/mission_control/jobs/dispatches_controller.rb +9 -4
- data/app/controllers/mission_control/jobs/jobs_controller.rb +0 -1
- data/app/controllers/mission_control/jobs/recurring_tasks_controller.rb +16 -1
- data/app/helpers/mission_control/jobs/jobs_helper.rb +10 -5
- data/app/models/mission_control/jobs/recurring_task.rb +8 -0
- data/app/views/layouts/mission_control/jobs/application.html.erb +2 -1
- data/app/views/mission_control/jobs/jobs/_general_information.html.erb +11 -0
- data/app/views/mission_control/jobs/jobs/blocked/_actions.html.erb +1 -1
- data/app/views/mission_control/jobs/jobs/blocked/_job.html.erb +3 -2
- data/app/views/mission_control/jobs/jobs/scheduled/_actions.html.erb +1 -0
- data/app/views/mission_control/jobs/recurring_tasks/_actions.html.erb +5 -0
- data/app/views/mission_control/jobs/recurring_tasks/_recurring_task.html.erb +3 -0
- data/app/views/mission_control/jobs/recurring_tasks/_title.html.erb +3 -0
- data/app/views/mission_control/jobs/recurring_tasks/index.html.erb +3 -2
- data/config/routes.rb +1 -1
- data/lib/active_job/executing.rb +1 -1
- data/lib/active_job/jobs_relation.rb +5 -0
- data/lib/active_job/queue_adapters/solid_queue_ext/recurring_tasks.rb +12 -0
- data/lib/active_job/queue_adapters/solid_queue_ext.rb +7 -3
- data/lib/mission_control/jobs/engine.rb +8 -0
- data/lib/mission_control/jobs/version.rb +1 -1
- metadata +7 -5
@@ -1,6 +1,14 @@
|
|
1
1
|
class MissionControl::Jobs::ApplicationController < MissionControl::Jobs.base_controller_class.constantize
|
2
|
+
ActionController::Base::MODULES.each do |mod|
|
3
|
+
include mod unless self < mod
|
4
|
+
end
|
5
|
+
|
2
6
|
layout "mission_control/jobs/application"
|
3
7
|
|
8
|
+
# Include helpers if not already included
|
9
|
+
helper MissionControl::Jobs::ApplicationHelper unless self < MissionControl::Jobs::ApplicationHelper
|
10
|
+
helper Importmap::ImportmapTagsHelper unless self < Importmap::ImportmapTagsHelper
|
11
|
+
|
4
12
|
include MissionControl::Jobs::ApplicationScoped, MissionControl::Jobs::NotFoundRedirections
|
5
13
|
include MissionControl::Jobs::AdapterFeatures
|
6
14
|
|
@@ -3,11 +3,16 @@ class MissionControl::Jobs::DispatchesController < MissionControl::Jobs::Applica
|
|
3
3
|
|
4
4
|
def create
|
5
5
|
@job.dispatch
|
6
|
-
redirect_to
|
6
|
+
redirect_to redirect_location, notice: "Dispatched job with id #{@job.job_id}"
|
7
7
|
end
|
8
8
|
|
9
9
|
private
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
def jobs_relation
|
11
|
+
ActiveJob.jobs
|
12
|
+
end
|
13
|
+
|
14
|
+
def redirect_location
|
15
|
+
status = @job.status.presence_in(supported_job_statuses) || :blocked
|
16
|
+
application_jobs_url(@application, status)
|
17
|
+
end
|
13
18
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
class MissionControl::Jobs::RecurringTasksController < MissionControl::Jobs::ApplicationController
|
2
2
|
before_action :ensure_supported_recurring_tasks
|
3
|
-
before_action :set_recurring_task, only: :show
|
3
|
+
before_action :set_recurring_task, only: [ :show, :update ]
|
4
|
+
before_action :ensure_recurring_task_can_be_enqueued, only: :update
|
4
5
|
|
5
6
|
def index
|
6
7
|
@recurring_tasks = MissionControl::Jobs::Current.server.recurring_tasks
|
@@ -10,6 +11,14 @@ class MissionControl::Jobs::RecurringTasksController < MissionControl::Jobs::App
|
|
10
11
|
@jobs_page = MissionControl::Jobs::Page.new(@recurring_task.jobs, page: params[:page].to_i)
|
11
12
|
end
|
12
13
|
|
14
|
+
def update
|
15
|
+
if (job = @recurring_task.enqueue) && job.successfully_enqueued?
|
16
|
+
redirect_to application_job_path(@application, job.job_id), notice: "Enqueued recurring task #{@recurring_task.id}"
|
17
|
+
else
|
18
|
+
redirect_to application_recurring_task_path(@application, @recurring_task.id), alert: "Something went wrong enqueuing this recurring task"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
13
22
|
private
|
14
23
|
def ensure_supported_recurring_tasks
|
15
24
|
unless recurring_tasks_supported?
|
@@ -20,4 +29,10 @@ class MissionControl::Jobs::RecurringTasksController < MissionControl::Jobs::App
|
|
20
29
|
def set_recurring_task
|
21
30
|
@recurring_task = MissionControl::Jobs::Current.server.find_recurring_task(params[:id])
|
22
31
|
end
|
32
|
+
|
33
|
+
def ensure_recurring_task_can_be_enqueued
|
34
|
+
unless @recurring_task.runnable?
|
35
|
+
redirect_to application_recurring_task_path(@application, @recurring_task.id), alert: "This task can't be enqueued"
|
36
|
+
end
|
37
|
+
end
|
23
38
|
end
|
@@ -26,7 +26,7 @@ module MissionControl::Jobs::JobsHelper
|
|
26
26
|
def attribute_names_for_job_status(status)
|
27
27
|
case status.to_s
|
28
28
|
when "failed" then [ "Error", "" ]
|
29
|
-
when "blocked" then [ "Queue", "Blocked by", "
|
29
|
+
when "blocked" then [ "Queue", "Blocked by", "" ]
|
30
30
|
when "finished" then [ "Queue", "Finished" ]
|
31
31
|
when "scheduled" then [ "Queue", "Scheduled", "" ]
|
32
32
|
when "in_progress" then [ "Queue", "Run by", "Running since" ]
|
@@ -39,7 +39,6 @@ module MissionControl::Jobs::JobsHelper
|
|
39
39
|
end
|
40
40
|
|
41
41
|
private
|
42
|
-
|
43
42
|
def renderable_job_arguments_for(job)
|
44
43
|
job.serialized_arguments.collect do |argument|
|
45
44
|
as_renderable_argument(argument)
|
@@ -53,7 +52,7 @@ module MissionControl::Jobs::JobsHelper
|
|
53
52
|
when Array
|
54
53
|
as_renderable_array(argument)
|
55
54
|
else
|
56
|
-
ActiveJob::Arguments.deserialize([ argument ])
|
55
|
+
ActiveJob::Arguments.deserialize([ argument ]).first
|
57
56
|
end
|
58
57
|
rescue ActiveJob::DeserializationError
|
59
58
|
argument.to_s
|
@@ -65,12 +64,18 @@ module MissionControl::Jobs::JobsHelper
|
|
65
64
|
argument["_aj_globalid"]
|
66
65
|
elsif argument["_aj_serialized"] == "ActiveJob::Serializers::ModuleSerializer"
|
67
66
|
argument["value"]
|
67
|
+
elsif argument["_aj_serialized"]
|
68
|
+
ActiveJob::Arguments.deserialize([ argument ]).first
|
68
69
|
else
|
69
|
-
|
70
|
+
argument.without("_aj_symbol_keys", "_aj_ruby2_keywords")
|
71
|
+
.transform_values { |v| as_renderable_argument(v) }
|
72
|
+
.map { |k, v| "#{k}: #{v}" }
|
73
|
+
.join(", ")
|
74
|
+
.then { |s| "{#{s}}" }
|
70
75
|
end
|
71
76
|
end
|
72
77
|
|
73
78
|
def as_renderable_array(argument)
|
74
|
-
"
|
79
|
+
"[#{argument.collect { |part| as_renderable_argument(part) }.join(", ")}]"
|
75
80
|
end
|
76
81
|
end
|
@@ -12,6 +12,14 @@ class MissionControl::Jobs::RecurringTask
|
|
12
12
|
ActiveJob::JobsRelation.new(queue_adapter: queue_adapter).where(recurring_task_id: id)
|
13
13
|
end
|
14
14
|
|
15
|
+
def enqueue
|
16
|
+
queue_adapter.enqueue_recurring_task(id)
|
17
|
+
end
|
18
|
+
|
19
|
+
def runnable?
|
20
|
+
queue_adapter.can_enqueue_recurring_task?(id)
|
21
|
+
end
|
22
|
+
|
15
23
|
private
|
16
24
|
attr_reader :queue_adapter
|
17
25
|
end
|
@@ -7,7 +7,8 @@
|
|
7
7
|
|
8
8
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
9
9
|
<meta name="turbo-cache-control" content="no-cache">
|
10
|
-
|
10
|
+
|
11
|
+
<%= stylesheet_link_tag "mission_control/jobs/bulma.min" %>
|
11
12
|
<%= stylesheet_link_tag "mission_control/jobs/application", "data-turbo-track": "reload" %>
|
12
13
|
<%= javascript_importmap_tags "application", importmap: MissionControl::Jobs.importmap %>
|
13
14
|
</head>
|
@@ -26,6 +26,17 @@
|
|
26
26
|
<%= formatted_time(job.enqueued_at.to_datetime) %>
|
27
27
|
</td>
|
28
28
|
</tr>
|
29
|
+
<% if job.scheduled? %>
|
30
|
+
<tr>
|
31
|
+
<th>Scheduled</th>
|
32
|
+
<td>
|
33
|
+
<%= formatted_time(job.scheduled_at) %>
|
34
|
+
<% if job_delayed?(job) %>
|
35
|
+
<div class="is-danger tag ml-4">delayed</div>
|
36
|
+
<% end %>
|
37
|
+
</td>
|
38
|
+
</tr>
|
39
|
+
<% end %>
|
29
40
|
<% if job.failed? %>
|
30
41
|
<tr>
|
31
42
|
<th>Failed</th>
|
@@ -1,3 +1,3 @@
|
|
1
1
|
<div class="buttons is-right">
|
2
|
-
<%= button_to "
|
2
|
+
<%= button_to "Run now", application_job_dispatch_path(@application, job.job_id), class: "button is-warning is-light mr-0" %>
|
3
3
|
</div>
|
@@ -1,6 +1,7 @@
|
|
1
1
|
<td><%= link_to job.queue_name, application_queue_path(@application, job.queue) %></td>
|
2
|
-
<td><div class="is-family-monospace is-size-7"><%= job.blocked_by %></div
|
3
|
-
<
|
2
|
+
<td><div class="is-family-monospace is-size-7"><%= job.blocked_by %></div>
|
3
|
+
<div class="has-text-grey is-size-7">Until <%= formatted_time(job.blocked_until) %></div>
|
4
|
+
</td>
|
4
5
|
<td class="pr-0">
|
5
6
|
<%= render "mission_control/jobs/jobs/blocked/actions", job: job %>
|
6
7
|
</td>
|
@@ -1,4 +1,5 @@
|
|
1
1
|
<div class="buttons is-right">
|
2
|
+
<%= button_to "Run now", application_job_dispatch_path(@application, job.job_id), class: "button is-warning is-light mr-0" %>
|
2
3
|
<%= button_to "Discard", application_job_discard_path(@application, job.job_id), class: "button is-danger is-light mr-0",
|
3
4
|
form: { data: { turbo_confirm: "This will delete the job and can't be undone. Are you sure?" } } %>
|
4
5
|
</div>
|
@@ -16,4 +16,7 @@
|
|
16
16
|
<td> <%= recurring_task.schedule %> </td>
|
17
17
|
<td><div class="has-text-grey"><%= recurring_task.last_enqueued_at ? formatted_time(recurring_task.last_enqueued_at) : "Never" %></div></td>
|
18
18
|
<td class="next_time"><div class="has-text-grey"><%= formatted_time(recurring_task.next_time) %></div></td>
|
19
|
+
<td class="pr-0">
|
20
|
+
<%= render "mission_control/jobs/recurring_tasks/actions", recurring_task: recurring_task %>
|
21
|
+
</td>
|
19
22
|
</tr>
|
data/config/routes.rb
CHANGED
@@ -20,7 +20,7 @@ MissionControl::Jobs::Engine.routes.draw do
|
|
20
20
|
resources :jobs, only: :index, path: ":status/jobs"
|
21
21
|
|
22
22
|
resources :workers, only: [ :index, :show ]
|
23
|
-
resources :recurring_tasks, only: [ :index, :show ]
|
23
|
+
resources :recurring_tasks, only: [ :index, :show, :update ]
|
24
24
|
end
|
25
25
|
|
26
26
|
# Allow referencing urls without providing an application_id. It will default to the first one.
|
data/lib/active_job/executing.rb
CHANGED
@@ -154,7 +154,12 @@ class ActiveJob::JobsRelation
|
|
154
154
|
end
|
155
155
|
|
156
156
|
# Dispatch the provided job.
|
157
|
+
#
|
158
|
+
# This operation is only valid for blocked or scheduled jobs. It will
|
159
|
+
# raise an error +ActiveJob::Errors::InvalidOperation+ otherwise.
|
157
160
|
def dispatch_job(job)
|
161
|
+
raise ActiveJob::Errors::InvalidOperation, "This operation can only be performed on blocked or scheduled jobs, but this job is #{job.status}" unless job.blocked? || job.scheduled?
|
162
|
+
|
158
163
|
queue_adapter.dispatch_job(job, self)
|
159
164
|
end
|
160
165
|
|
@@ -20,6 +20,18 @@ module ActiveJob::QueueAdapters::SolidQueueExt::RecurringTasks
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
+
def enqueue_recurring_task(task_id)
|
24
|
+
if task = SolidQueue::RecurringTask.find_by(key: task_id)
|
25
|
+
task.enqueue(at: Time.now)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def can_enqueue_recurring_task?(task_id)
|
30
|
+
if task = SolidQueue::RecurringTask.find_by(key: task_id)
|
31
|
+
task.valid?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
23
35
|
private
|
24
36
|
def recurring_task_attributes_from_solid_queue_recurring_task(task)
|
25
37
|
{
|
@@ -123,9 +123,13 @@ module ActiveJob::QueueAdapters::SolidQueueExt
|
|
123
123
|
end
|
124
124
|
|
125
125
|
def dispatch_immediately(job)
|
126
|
-
|
127
|
-
|
128
|
-
|
126
|
+
if job.blocked?
|
127
|
+
SolidQueue::Job.transaction do
|
128
|
+
job.dispatch_bypassing_concurrency_limits
|
129
|
+
job.blocked_execution.destroy!
|
130
|
+
end
|
131
|
+
else
|
132
|
+
job.scheduled_execution.update!(scheduled_at: Time.now)
|
129
133
|
end
|
130
134
|
end
|
131
135
|
|
@@ -7,6 +7,13 @@ module MissionControl
|
|
7
7
|
class Engine < ::Rails::Engine
|
8
8
|
isolate_namespace MissionControl::Jobs
|
9
9
|
|
10
|
+
initializer "mission_control-jobs.middleware" do |app|
|
11
|
+
if app.config.api_only
|
12
|
+
app.middleware.use ActionDispatch::Flash
|
13
|
+
app.middleware.use ::Rack::MethodOverride
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
10
17
|
config.mission_control = ActiveSupport::OrderedOptions.new unless config.try(:mission_control)
|
11
18
|
config.mission_control.jobs = ActiveSupport::OrderedOptions.new
|
12
19
|
|
@@ -80,6 +87,7 @@ module MissionControl
|
|
80
87
|
end
|
81
88
|
|
82
89
|
initializer "mission_control-jobs.assets" do |app|
|
90
|
+
app.config.assets.paths << root.join("app/assets/stylesheets")
|
83
91
|
app.config.assets.paths << root.join("app/javascript")
|
84
92
|
app.config.assets.precompile += %w[ mission_control_jobs_manifest ]
|
85
93
|
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.
|
4
|
+
version: 0.6.0
|
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-11-
|
11
|
+
date: 2024-11-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -156,14 +156,14 @@ dependencies:
|
|
156
156
|
requirements:
|
157
157
|
- - "~>"
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version:
|
159
|
+
version: 1.0.1
|
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:
|
166
|
+
version: 1.0.1
|
167
167
|
- !ruby/object:Gem::Dependency
|
168
168
|
name: selenium-webdriver
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
@@ -305,7 +305,7 @@ dependencies:
|
|
305
305
|
- !ruby/object:Gem::Version
|
306
306
|
version: '0'
|
307
307
|
- !ruby/object:Gem::Dependency
|
308
|
-
name:
|
308
|
+
name: propshaft
|
309
309
|
requirement: !ruby/object:Gem::Requirement
|
310
310
|
requirements:
|
311
311
|
- - ">="
|
@@ -358,6 +358,7 @@ files:
|
|
358
358
|
- Rakefile
|
359
359
|
- app/assets/config/mission_control_jobs_manifest.js
|
360
360
|
- app/assets/stylesheets/mission_control/jobs/application.css
|
361
|
+
- app/assets/stylesheets/mission_control/jobs/bulma.min.css
|
361
362
|
- app/assets/stylesheets/mission_control/jobs/forms.css
|
362
363
|
- app/assets/stylesheets/mission_control/jobs/jobs.css
|
363
364
|
- app/controllers/concerns/mission_control/jobs/adapter_features.rb
|
@@ -425,6 +426,7 @@ files:
|
|
425
426
|
- app/views/mission_control/jobs/queues/_queue_title.html.erb
|
426
427
|
- app/views/mission_control/jobs/queues/index.html.erb
|
427
428
|
- app/views/mission_control/jobs/queues/show.html.erb
|
429
|
+
- app/views/mission_control/jobs/recurring_tasks/_actions.html.erb
|
428
430
|
- app/views/mission_control/jobs/recurring_tasks/_general_information.html.erb
|
429
431
|
- app/views/mission_control/jobs/recurring_tasks/_recurring_task.html.erb
|
430
432
|
- app/views/mission_control/jobs/recurring_tasks/_title.html.erb
|