mission_control-jobs 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +244 -0
- data/Rakefile +8 -0
- data/app/assets/config/mission_control_jobs_manifest.js +4 -0
- data/app/assets/stylesheets/mission_control/jobs/application.css +16 -0
- data/app/assets/stylesheets/mission_control/jobs/forms.css +8 -0
- data/app/assets/stylesheets/mission_control/jobs/jobs.css +7 -0
- data/app/controllers/concerns/mission_control/jobs/adapter_features.rb +20 -0
- data/app/controllers/concerns/mission_control/jobs/application_scoped.rb +38 -0
- data/app/controllers/concerns/mission_control/jobs/failed_jobs_bulk_operations.rb +17 -0
- data/app/controllers/concerns/mission_control/jobs/job_filters.rb +18 -0
- data/app/controllers/concerns/mission_control/jobs/job_scoped.rb +16 -0
- data/app/controllers/concerns/mission_control/jobs/not_found_redirections.rb +25 -0
- data/app/controllers/concerns/mission_control/jobs/queue_scoped.rb +12 -0
- data/app/controllers/mission_control/jobs/application_controller.rb +11 -0
- data/app/controllers/mission_control/jobs/bulk_discards_controller.rb +20 -0
- data/app/controllers/mission_control/jobs/bulk_retries_controller.rb +10 -0
- data/app/controllers/mission_control/jobs/discards_controller.rb +13 -0
- data/app/controllers/mission_control/jobs/jobs_controller.rb +37 -0
- data/app/controllers/mission_control/jobs/queues/pauses_controller.rb +15 -0
- data/app/controllers/mission_control/jobs/queues_controller.rb +24 -0
- data/app/controllers/mission_control/jobs/retries_controller.rb +13 -0
- data/app/controllers/mission_control/jobs/workers_controller.rb +18 -0
- data/app/helpers/mission_control/jobs/application_helper.rb +8 -0
- data/app/helpers/mission_control/jobs/dates_helper.rb +19 -0
- data/app/helpers/mission_control/jobs/jobs_helper.rb +63 -0
- data/app/helpers/mission_control/jobs/navigation_helper.rb +51 -0
- data/app/helpers/mission_control/jobs/ui_helper.rb +23 -0
- data/app/javascript/mission_control/jobs/application.js +4 -0
- data/app/javascript/mission_control/jobs/controllers/application.js +9 -0
- data/app/javascript/mission_control/jobs/controllers/form_controller.js +21 -0
- data/app/javascript/mission_control/jobs/controllers/index.js +11 -0
- data/app/javascript/mission_control/jobs/helpers/debounce_helpers.js +9 -0
- data/app/javascript/mission_control/jobs/helpers/index.js +1 -0
- data/app/jobs/mission_control/jobs/application_job.rb +6 -0
- data/app/mailers/mission_control/jobs/application_mailer.rb +8 -0
- data/app/models/mission_control/jobs/application_record.rb +7 -0
- data/app/models/mission_control/jobs/current.rb +3 -0
- data/app/models/mission_control/jobs/page.rb +48 -0
- data/app/models/mission_control/jobs/worker.rb +17 -0
- data/app/views/layouts/mission_control/jobs/_application_selection.html.erb +11 -0
- data/app/views/layouts/mission_control/jobs/_flash.html.erb +9 -0
- data/app/views/layouts/mission_control/jobs/_navigation.html.erb +9 -0
- data/app/views/layouts/mission_control/jobs/application.html.erb +25 -0
- data/app/views/layouts/mission_control/jobs/application_selection/_applications.html.erb +13 -0
- data/app/views/layouts/mission_control/jobs/application_selection/_servers.html.erb +15 -0
- data/app/views/mission_control/jobs/jobs/_error_information.html.erb +19 -0
- data/app/views/mission_control/jobs/jobs/_filters.html.erb +35 -0
- data/app/views/mission_control/jobs/jobs/_general_information.html.erb +54 -0
- data/app/views/mission_control/jobs/jobs/_job.html.erb +13 -0
- data/app/views/mission_control/jobs/jobs/_jobs_page.html.erb +15 -0
- data/app/views/mission_control/jobs/jobs/_raw_data.html.erb +4 -0
- data/app/views/mission_control/jobs/jobs/_title.html.erb +13 -0
- data/app/views/mission_control/jobs/jobs/_toolbar.html.erb +18 -0
- data/app/views/mission_control/jobs/jobs/blocked/_job.html.erb +3 -0
- data/app/views/mission_control/jobs/jobs/failed/_actions.html.erb +5 -0
- data/app/views/mission_control/jobs/jobs/failed/_job.html.erb +7 -0
- data/app/views/mission_control/jobs/jobs/finished/_job.html.erb +2 -0
- data/app/views/mission_control/jobs/jobs/in_progress/_job.html.erb +9 -0
- data/app/views/mission_control/jobs/jobs/index.html.erb +19 -0
- data/app/views/mission_control/jobs/jobs/scheduled/_job.html.erb +7 -0
- data/app/views/mission_control/jobs/jobs/show.html.erb +6 -0
- data/app/views/mission_control/jobs/queues/_actions.html.erb +7 -0
- data/app/views/mission_control/jobs/queues/_job.html.erb +15 -0
- data/app/views/mission_control/jobs/queues/_queue.html.erb +16 -0
- data/app/views/mission_control/jobs/queues/_queue_title.html.erb +17 -0
- data/app/views/mission_control/jobs/queues/index.html.erb +16 -0
- data/app/views/mission_control/jobs/queues/show.html.erb +25 -0
- data/app/views/mission_control/jobs/shared/_pagination_toolbar.html.erb +5 -0
- data/app/views/mission_control/jobs/workers/_configuration.html.erb +6 -0
- data/app/views/mission_control/jobs/workers/_job.html.erb +19 -0
- data/app/views/mission_control/jobs/workers/_jobs.html.erb +20 -0
- data/app/views/mission_control/jobs/workers/_raw_data.html.erb +6 -0
- data/app/views/mission_control/jobs/workers/_title.html.erb +11 -0
- data/app/views/mission_control/jobs/workers/_worker.html.erb +21 -0
- data/app/views/mission_control/jobs/workers/index.html.erb +17 -0
- data/app/views/mission_control/jobs/workers/show.html.erb +7 -0
- data/config/importmap.rb +6 -0
- data/config/routes.rb +33 -0
- data/lib/active_job/errors/invalid_operation.rb +5 -0
- data/lib/active_job/errors/job_not_found_error.rb +14 -0
- data/lib/active_job/errors/query_error.rb +5 -0
- data/lib/active_job/executing.rb +43 -0
- data/lib/active_job/execution_error.rb +8 -0
- data/lib/active_job/failed.rb +11 -0
- data/lib/active_job/job_proxy.rb +26 -0
- data/lib/active_job/jobs_relation.rb +300 -0
- data/lib/active_job/querying.rb +44 -0
- data/lib/active_job/queue.rb +62 -0
- data/lib/active_job/queue_adapters/resque_ext.rb +300 -0
- data/lib/active_job/queue_adapters/solid_queue_ext.rb +294 -0
- data/lib/active_job/queues.rb +29 -0
- data/lib/mission_control/jobs/adapter.rb +108 -0
- data/lib/mission_control/jobs/application.rb +17 -0
- data/lib/mission_control/jobs/applications.rb +8 -0
- data/lib/mission_control/jobs/console/context.rb +11 -0
- data/lib/mission_control/jobs/console/helpers.rb +26 -0
- data/lib/mission_control/jobs/engine.rb +88 -0
- data/lib/mission_control/jobs/errors/incompatible_adapter.rb +2 -0
- data/lib/mission_control/jobs/errors/resource_not_found.rb +2 -0
- data/lib/mission_control/jobs/identified_by_name.rb +18 -0
- data/lib/mission_control/jobs/identified_elements.rb +23 -0
- data/lib/mission_control/jobs/server/serializable.rb +24 -0
- data/lib/mission_control/jobs/server/workers.rb +15 -0
- data/lib/mission_control/jobs/server.rb +26 -0
- data/lib/mission_control/jobs/version.rb +5 -0
- data/lib/mission_control/jobs.rb +19 -0
- data/lib/resque/thread_safe_redis.rb +34 -0
- data/lib/tasks/mission_control/jobs_tasks.rake +4 -0
- metadata +364 -0
@@ -0,0 +1,7 @@
|
|
1
|
+
<td><%= link_to job.queue_name, application_queue_path(@application, job.queue) %></td>
|
2
|
+
<td>
|
3
|
+
<%= bidirectional_time_distance_in_words_with_title(job.scheduled_at) %>
|
4
|
+
<% if job.scheduled_at.before? 1.minute.ago %>
|
5
|
+
<div class="is-danger tag ml-4">delayed</div>
|
6
|
+
<% end %>
|
7
|
+
</td>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<% navigation(title: "Job #{@job.job_id}", section: navigation_section_for_status(@job.status)) %>
|
2
|
+
|
3
|
+
<%= render "mission_control/jobs/jobs/title", job: @job %>
|
4
|
+
<%= render "mission_control/jobs/jobs/general_information", job: @job %>
|
5
|
+
<%= render "mission_control/jobs/jobs/error_information", job: @job %>
|
6
|
+
<%= render "mission_control/jobs/jobs/raw_data", job: @job %>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<div class="buttons is-right">
|
2
|
+
<% if queue.active? %>
|
3
|
+
<%= button_to "Pause", application_queue_pause_path(@application, queue.name), method: :post, class: "button is-success is-light mr-0" %>
|
4
|
+
<% else %>
|
5
|
+
<%= button_to "Resume", application_queue_pause_path(@application, queue.name), method: :delete, class: "button is-warning is-light mr-0" %>
|
6
|
+
<% end %>
|
7
|
+
</div>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<tr class="job">
|
2
|
+
<td>
|
3
|
+
<%= link_to application_job_path(@application, job.job_id, filter: { queue_name: job.queue }) do %>
|
4
|
+
<%= job_title(job) %>
|
5
|
+
<% end %>
|
6
|
+
<div class="has-text-grey">Enqueued <%= time_ago_in_words_with_title(job.enqueued_at.to_datetime) %> ago</div>
|
7
|
+
</td>
|
8
|
+
<td>
|
9
|
+
<% if job.serialized_arguments.present? %>
|
10
|
+
<span class="is-family-monospace">
|
11
|
+
<%= job_arguments(job) %>
|
12
|
+
</span>
|
13
|
+
<% end %>
|
14
|
+
</td>
|
15
|
+
</tr>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<tr class="queue">
|
2
|
+
<td>
|
3
|
+
<%= link_to queue.name, application_queue_path(@application, queue.name) %>
|
4
|
+
<% if queue.paused? %>
|
5
|
+
<span class="ml-4 tag is-warning">Paused</span>
|
6
|
+
<% end %>
|
7
|
+
</td>
|
8
|
+
<td>
|
9
|
+
<%= queue.size %>
|
10
|
+
</td>
|
11
|
+
<td class="pr-0">
|
12
|
+
<% if queue_pausing_supported? %>
|
13
|
+
<%= render "mission_control/jobs/queues/actions", queue: queue %>
|
14
|
+
<% end %>
|
15
|
+
</td>
|
16
|
+
</tr>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<h1 class="title">
|
2
|
+
<div class="level">
|
3
|
+
<div class="level-left">
|
4
|
+
<%= queue.name %>
|
5
|
+
<% if queue.paused? %>
|
6
|
+
<span class="ml-4 tag is-warning">Paused</span>
|
7
|
+
<% end %>
|
8
|
+
</div>
|
9
|
+
<% if queue_pausing_supported? %>
|
10
|
+
<div class="level-right">
|
11
|
+
<%= render "mission_control/jobs/queues/actions", queue: queue %>
|
12
|
+
</div>
|
13
|
+
<% end %>
|
14
|
+
</div>
|
15
|
+
</h1>
|
16
|
+
|
17
|
+
<h2 class="subtitle"><%= queue.size %> pending jobs</h2>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<% navigation(title: "Queues", section: :queues) %>
|
2
|
+
|
3
|
+
<table class="queues table is-hoverable is-fullwidth">
|
4
|
+
<tbody>
|
5
|
+
<thead>
|
6
|
+
<tr>
|
7
|
+
<th style="width: 50%;">Queue</th>
|
8
|
+
<th style="width: 30%;">Pending jobs</th>
|
9
|
+
<th></th>
|
10
|
+
</tr>
|
11
|
+
</thead>
|
12
|
+
|
13
|
+
<%= render partial: "mission_control/jobs/queues/queue", collection: @queues %>
|
14
|
+
|
15
|
+
</tbody>
|
16
|
+
</table>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<% navigation(title: "Queue #{@queue.name}", section: :queues) %>
|
2
|
+
|
3
|
+
<%= render "mission_control/jobs/queues/queue_title", queue: @queue %>
|
4
|
+
|
5
|
+
<% if @jobs_page.empty? %>
|
6
|
+
<%= blank_status_notice "The queue is empty" %>
|
7
|
+
<% else %>
|
8
|
+
<table class="jobs table queues is-hoverable is-fullwidth">
|
9
|
+
<tbody>
|
10
|
+
<thead>
|
11
|
+
<tr>
|
12
|
+
<th style="width: 30%;">Job</th>
|
13
|
+
<th></th>
|
14
|
+
</tr>
|
15
|
+
</thead>
|
16
|
+
|
17
|
+
<%= render partial: "mission_control/jobs/queues/job", collection: @jobs_page.jobs %>
|
18
|
+
|
19
|
+
</tbody>
|
20
|
+
</table>
|
21
|
+
|
22
|
+
<%= render "mission_control/jobs/shared/pagination_toolbar", jobs_page: @jobs_page %>
|
23
|
+
<% end %>
|
24
|
+
|
25
|
+
|
@@ -0,0 +1,5 @@
|
|
1
|
+
<nav class="buttons is-right" role="navigation" aria-label="pagination">
|
2
|
+
<span class="mr-3"><%= jobs_page.index %> / <%= jobs_page.pages_count || "..." %></span>
|
3
|
+
<%= link_to "Previous page", url_for(page: jobs_page.previous_index, **jobs_filter_param), class: "pagination-previous", disabled: jobs_page.first? %>
|
4
|
+
<%= link_to "Next page", url_for(page: jobs_page.next_index, **jobs_filter_param), class: "pagination-next", disabled: jobs_page.last? %>
|
5
|
+
</nav>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<tr class="job">
|
2
|
+
<td>
|
3
|
+
<%= link_to application_job_path(@application, job.job_id, filter: { queue_name: job.queue }) do %>
|
4
|
+
<%= job_title(job) %>
|
5
|
+
<% end %>
|
6
|
+
<div class="has-text-grey">Enqueued <%= time_ago_in_words_with_title(job.enqueued_at.to_datetime) %> ago</div>
|
7
|
+
</td>
|
8
|
+
<td>
|
9
|
+
<% if job.serialized_arguments.present? %>
|
10
|
+
<span class="is-family-monospace">
|
11
|
+
<%= job_arguments(job) %>
|
12
|
+
</span>
|
13
|
+
<% end %>
|
14
|
+
</td>
|
15
|
+
|
16
|
+
<td>
|
17
|
+
<div class="has-text-grey"><%= job.started_at ? time_distance_in_words_with_title(job.started_at) : "(Finished)" %></div>
|
18
|
+
</td>
|
19
|
+
</tr>
|
@@ -0,0 +1,20 @@
|
|
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 %>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<tr class="worker">
|
2
|
+
<td>
|
3
|
+
<%= link_to "worker #{worker.id}", application_worker_path(@application, worker.id) %>
|
4
|
+
<br />
|
5
|
+
<%= worker.name %>
|
6
|
+
</td>
|
7
|
+
<td><%= worker.hostname %></td>
|
8
|
+
<td>
|
9
|
+
<% worker.jobs.each do |job| %>
|
10
|
+
<div>
|
11
|
+
<%= link_to job_title(job), application_job_path(@application, job.job_id) %>
|
12
|
+
|
13
|
+
<% if job.serialized_arguments.present? %>
|
14
|
+
<div class="is-family-monospace is-size-7"><%= job_arguments(job) %></div>
|
15
|
+
<% end %>
|
16
|
+
</div>
|
17
|
+
<% end %>
|
18
|
+
</td>
|
19
|
+
|
20
|
+
<td><div class="has-text-grey"><%= time_ago_in_words_with_title(worker.last_heartbeat_at) %> ago</div></td>
|
21
|
+
</tr>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<% navigation(title: "Workers", section: :workers) %>
|
2
|
+
|
3
|
+
<table class="workers table jobs is-hoverable is-fullwidth">
|
4
|
+
<tbody>
|
5
|
+
<thead>
|
6
|
+
<tr>
|
7
|
+
<th>Worker</th>
|
8
|
+
<th>Hostname</th>
|
9
|
+
<th style="width: 35%;">Jobs</th>
|
10
|
+
<th>Last heartbeat</th>
|
11
|
+
</tr>
|
12
|
+
</thead>
|
13
|
+
|
14
|
+
<%= render partial: "mission_control/jobs/workers/worker", collection: @workers %>
|
15
|
+
|
16
|
+
</tbody>
|
17
|
+
</table>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<% navigation(title: "Worker #{@worker.id}", section: :workers) %>
|
2
|
+
|
3
|
+
<%= render "mission_control/jobs/workers/title", worker: @worker %>
|
4
|
+
<%= render "mission_control/jobs/workers/configuration", worker: @worker %>
|
5
|
+
<%= render "mission_control/jobs/workers/jobs", worker: @worker %>
|
6
|
+
<%= render "mission_control/jobs/workers/raw_data", worker: @worker %>
|
7
|
+
|
data/config/importmap.rb
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
pin "application-mcj", to: "mission_control/jobs/application.js", preload: true
|
2
|
+
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
|
3
|
+
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
|
4
|
+
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
|
5
|
+
pin_all_from MissionControl::Jobs::Engine.root.join("app/javascript/mission_control/jobs/controllers"), under: "controllers", to: "mission_control/jobs/controllers"
|
6
|
+
pin_all_from MissionControl::Jobs::Engine.root.join("app/javascript/mission_control/jobs/helpers"), under: "helpers", to: "mission_control/jobs/helpers"
|
data/config/routes.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
MissionControl::Jobs::Engine.routes.draw do
|
2
|
+
resources :applications, only: [] do
|
3
|
+
resources :queues, only: [ :index, :show ] do
|
4
|
+
scope module: :queues do
|
5
|
+
resource :pause, only: [ :create, :destroy ]
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
resources :jobs, only: :show do
|
10
|
+
resource :retry, only: :create
|
11
|
+
resource :discard, only: :create
|
12
|
+
|
13
|
+
collection do
|
14
|
+
resource :bulk_retries, only: :create
|
15
|
+
resource :bulk_discards, only: :create
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
resources :jobs, only: :index, path: ":status/jobs"
|
20
|
+
|
21
|
+
resources :workers, only: [ :index, :show ]
|
22
|
+
end
|
23
|
+
|
24
|
+
# Allow referencing urls without providing an application_id. It will default to the first one.
|
25
|
+
resources :queues, only: [ :index, :show ]
|
26
|
+
|
27
|
+
resources :jobs, only: :show
|
28
|
+
resources :jobs, only: :index, path: ":status/jobs"
|
29
|
+
|
30
|
+
resources :workers, only: [ :index, :show ]
|
31
|
+
|
32
|
+
root to: "queues#index"
|
33
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module ActiveJob
|
2
|
+
module Errors
|
3
|
+
class JobNotFoundError < StandardError
|
4
|
+
attr_reader :job_relation
|
5
|
+
|
6
|
+
def initialize(job_or_job_id, job_relation)
|
7
|
+
@job_relation = job_relation
|
8
|
+
|
9
|
+
job_id = job_or_job_id.is_a?(ActiveJob::Base) ? job_or_job_id.job_id : job_or_job_id
|
10
|
+
super "Job with id '#{job_id}' not found"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# TODO: These (or a version of them) should be moved to +ActiveJob::Core+
|
2
|
+
# and related concerns when upstreamed.
|
3
|
+
module ActiveJob::Executing
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
attr_accessor :raw_data, :position, :finished_at, :blocked_by, :blocked_until, :worker_id, :started_at
|
8
|
+
attr_reader :serialized_arguments
|
9
|
+
attr_writer :status
|
10
|
+
|
11
|
+
thread_cattr_accessor :current_queue_adapter
|
12
|
+
end
|
13
|
+
|
14
|
+
class_methods do
|
15
|
+
def queue_adapter
|
16
|
+
ActiveJob::Base.current_queue_adapter || super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def retry
|
21
|
+
ActiveJob.jobs.failed.retry_job(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
def discard
|
25
|
+
jobs_relation_for_discarding.discard_job(self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def status
|
29
|
+
return @status if @status.present?
|
30
|
+
|
31
|
+
failed? ? :failed : :pending
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def jobs_relation_for_discarding
|
36
|
+
case status
|
37
|
+
when :failed then ActiveJob.jobs.failed
|
38
|
+
when :pending then ActiveJob.jobs.pending.where(queue_name: queue_name)
|
39
|
+
else
|
40
|
+
ActiveJob.jobs
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# Information about a given error when executing a job.
|
2
|
+
#
|
3
|
+
# It's attached to failed jobs at +ActiveJob::Base#last_execution_error+.
|
4
|
+
ActiveJob::ExecutionError = Struct.new(:error_class, :message, :backtrace, keyword_init: true) do
|
5
|
+
def to_s
|
6
|
+
"ERROR #{error_class}: #{message}\n#{backtrace&.collect { |line| "\t#{line}" }&.join("\n")}"
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# A proxy for managing jobs without having to load the corresponding
|
2
|
+
# job class.
|
3
|
+
#
|
4
|
+
# This is useful for managing jobs without having the job classes
|
5
|
+
# present in the code base.
|
6
|
+
class ActiveJob::JobProxy < ActiveJob::Base
|
7
|
+
class UnsupportedError < StandardError; end
|
8
|
+
|
9
|
+
attr_reader :job_class_name
|
10
|
+
|
11
|
+
def initialize(job_data)
|
12
|
+
super
|
13
|
+
@job_class_name = job_data["job_class"]
|
14
|
+
deserialize(job_data)
|
15
|
+
end
|
16
|
+
|
17
|
+
def serialize
|
18
|
+
super.tap do |json|
|
19
|
+
json["job_class"] = @job_class_name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def perform_now
|
24
|
+
raise UnsupportedError, "A JobProxy doesn't support immediate execution, only enqueuing."
|
25
|
+
end
|
26
|
+
end
|