good_job 2.5.0 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +1 -1
- data/engine/app/assets/vendor/rails_ujs.js +747 -0
- data/engine/app/controllers/good_job/assets_controller.rb +4 -0
- data/engine/app/controllers/good_job/cron_entries_controller.rb +19 -0
- data/engine/app/filters/good_job/base_filter.rb +6 -5
- data/engine/app/filters/good_job/executions_filter.rb +1 -1
- data/engine/app/filters/good_job/jobs_filter.rb +1 -1
- data/engine/app/views/good_job/cron_entries/index.html.erb +51 -0
- data/engine/app/views/good_job/cron_entries/show.html.erb +4 -0
- data/engine/app/views/good_job/{shared/_executions_table.erb → executions/_table.erb} +1 -1
- data/engine/app/views/good_job/executions/index.html.erb +1 -1
- data/engine/app/views/good_job/{shared/_jobs_table.erb → jobs/_table.erb} +3 -3
- data/engine/app/views/good_job/jobs/index.html.erb +1 -1
- data/engine/app/views/good_job/jobs/show.html.erb +2 -2
- data/engine/app/views/good_job/shared/_filter.erb +9 -10
- data/engine/app/views/good_job/shared/icons/_play.html.erb +4 -0
- data/engine/app/views/layouts/good_job/base.html.erb +2 -1
- data/engine/config/routes.rb +8 -1
- data/{engine/app/models → lib}/good_job/active_job_job.rb +0 -0
- data/lib/good_job/configuration.rb +1 -1
- data/lib/good_job/cron_entry.rb +75 -4
- data/lib/good_job/cron_manager.rb +1 -5
- data/lib/good_job/current_thread.rb +26 -8
- data/lib/good_job/execution.rb +15 -13
- data/lib/good_job/version.rb +1 -1
- metadata +14 -11
- data/engine/app/controllers/good_job/cron_schedules_controller.rb +0 -9
- data/engine/app/views/good_job/cron_schedules/index.html.erb +0 -72
@@ -23,6 +23,10 @@ module GoodJob
|
|
23
23
|
render file: GoodJob::Engine.root.join("app", "assets", "vendor", "chartist", "chartist.js")
|
24
24
|
end
|
25
25
|
|
26
|
+
def rails_ujs_js
|
27
|
+
render file: GoodJob::Engine.root.join("app", "assets", "vendor", "rails_ujs.js")
|
28
|
+
end
|
29
|
+
|
26
30
|
def style_css
|
27
31
|
render file: GoodJob::Engine.root.join("app", "assets", "style.css")
|
28
32
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GoodJob
|
3
|
+
class CronEntriesController < GoodJob::BaseController
|
4
|
+
def index
|
5
|
+
@cron_entries = CronEntry.all
|
6
|
+
end
|
7
|
+
|
8
|
+
def show
|
9
|
+
@cron_entry = CronEntry.find(params[:id])
|
10
|
+
@jobs_filter = JobsFilter.new(params, @cron_entry.jobs)
|
11
|
+
end
|
12
|
+
|
13
|
+
def enqueue
|
14
|
+
@cron_entry = CronEntry.find(params[:id])
|
15
|
+
@cron_entry.enqueue(Time.current)
|
16
|
+
redirect_back(fallback_location: cron_entries_path, notice: "Cron entry has been enqueued.")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -3,10 +3,11 @@ module GoodJob
|
|
3
3
|
class BaseFilter
|
4
4
|
DEFAULT_LIMIT = 25
|
5
5
|
|
6
|
-
attr_accessor :params
|
6
|
+
attr_accessor :params, :base_query
|
7
7
|
|
8
|
-
def initialize(params)
|
8
|
+
def initialize(params, base_query = nil)
|
9
9
|
@params = params
|
10
|
+
@base_query = base_query || default_base_query
|
10
11
|
end
|
11
12
|
|
12
13
|
def records
|
@@ -24,13 +25,13 @@ module GoodJob
|
|
24
25
|
|
25
26
|
def job_classes
|
26
27
|
base_query.group("serialized_params->>'job_class'").count
|
27
|
-
.sort_by { |name, _count| name }
|
28
|
+
.sort_by { |name, _count| name.to_s }
|
28
29
|
.to_h
|
29
30
|
end
|
30
31
|
|
31
32
|
def queues
|
32
33
|
base_query.group(:queue_name).count
|
33
|
-
.sort_by { |name, _count| name }
|
34
|
+
.sort_by { |name, _count| name.to_s }
|
34
35
|
.to_h
|
35
36
|
end
|
36
37
|
|
@@ -94,7 +95,7 @@ module GoodJob
|
|
94
95
|
|
95
96
|
private
|
96
97
|
|
97
|
-
def
|
98
|
+
def default_base_query
|
98
99
|
raise NotImplementedError
|
99
100
|
end
|
100
101
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
<% if @cron_entries.present? %>
|
2
|
+
<div class="card my-3">
|
3
|
+
<div class="table-responsive">
|
4
|
+
<table class="table card-table table-bordered table-hover table-sm mb-0">
|
5
|
+
<thead>
|
6
|
+
<th>Key</th>
|
7
|
+
<th>Schedule</th>
|
8
|
+
<th>
|
9
|
+
Properties
|
10
|
+
<%= tag.button "Toggle", type: "button", class: "btn btn-sm btn-outline-primary", role: "button",
|
11
|
+
data: { bs_toggle: "collapse", bs_target: ".cron-entry-properties" },
|
12
|
+
aria: { expanded: false, controls: @cron_entries.map { |cron_entry| "##{dom_id(cron_entry, 'properties')}" }.join(" ") }
|
13
|
+
%>
|
14
|
+
</th>
|
15
|
+
<th>Description</th>
|
16
|
+
<th>Next scheduled</th>
|
17
|
+
<th>Last run</th>
|
18
|
+
<th>Actions</th>
|
19
|
+
</thead>
|
20
|
+
<tbody>
|
21
|
+
<% @cron_entries.each do |cron_entry| %>
|
22
|
+
<tr id="<%= dom_id(cron_entry) %>">
|
23
|
+
<td class="font-monospace"><%= cron_entry.key %></td>
|
24
|
+
<td class="font-monospace"><%= cron_entry.schedule %></td>
|
25
|
+
<td>
|
26
|
+
<%= tag.button("Preview", type: "button", class: "btn btn-sm btn-outline-primary", role: "button",
|
27
|
+
data: { bs_toggle: "collapse", bs_target: "##{dom_id(cron_entry, 'properties')}" },
|
28
|
+
aria: { expanded: false, controls: dom_id(cron_entry, 'properties') }) %>
|
29
|
+
<%= tag.pre(JSON.pretty_generate(cron_entry.display_properties), id: dom_id(cron_entry, 'properties'), class: "collapse cron-entry-properties") %>
|
30
|
+
</td>
|
31
|
+
<td><%= cron_entry.description %></td>
|
32
|
+
<td><%= cron_entry.next_at %></td>
|
33
|
+
<td>
|
34
|
+
<% if cron_entry.last_job.present? %>
|
35
|
+
<%= link_to cron_entry.last_at, cron_entry_path(cron_entry), title: "Job #{cron_entry.last_job.id}" %>
|
36
|
+
<% end %>
|
37
|
+
</td>
|
38
|
+
<td>
|
39
|
+
<%= button_to enqueue_cron_entry_path(cron_entry.id), method: :post, class: "btn btn-sm btn-outline-primary", form_class: "d-inline-block", aria: { label: "Run cron entry now" }, title: "Run cron entry now", data: { confirm: "Confirm run cron entry now" } do %>
|
40
|
+
<%= render "good_job/shared/icons/play" %>
|
41
|
+
<% end %>
|
42
|
+
</td>
|
43
|
+
</tr>
|
44
|
+
<% end %>
|
45
|
+
</tbody>
|
46
|
+
</table>
|
47
|
+
</div>
|
48
|
+
</div>
|
49
|
+
<% else %>
|
50
|
+
<em>No cron schedules present.</em>
|
51
|
+
<% end %>
|
@@ -44,7 +44,7 @@
|
|
44
44
|
<%= tag.pre JSON.pretty_generate(execution.serialized_params), id: dom_id(execution, "params"), class: "collapse job-params" %>
|
45
45
|
</td>
|
46
46
|
<td>
|
47
|
-
<%= button_to execution_path(execution.id), method: :delete, class: "btn btn-sm btn-outline-danger", title: "Delete execution" do %>
|
47
|
+
<%= button_to execution_path(execution.id), method: :delete, class: "btn btn-sm btn-outline-danger", title: "Delete execution", data: { confirm: "Confirm delete" } do %>
|
48
48
|
<%= render "good_job/shared/icons/trash" %>
|
49
49
|
<% end %>
|
50
50
|
</td>
|
@@ -5,7 +5,7 @@
|
|
5
5
|
<%= render 'good_job/shared/filter', filter: @filter %>
|
6
6
|
|
7
7
|
<% if @filter.records.present? %>
|
8
|
-
<%= render 'good_job/
|
8
|
+
<%= render 'good_job/executions/table', executions: @filter.records %>
|
9
9
|
|
10
10
|
<nav aria-label="Job pagination" class="mt-3">
|
11
11
|
<ul class="pagination">
|
@@ -46,16 +46,16 @@
|
|
46
46
|
<td>
|
47
47
|
<div class="text-nowrap">
|
48
48
|
<% job_reschedulable = job.status.in? [:scheduled, :retried, :queued] %>
|
49
|
-
<%= button_to reschedule_job_path(job.id), method: :put, class: "btn btn-sm #{job_reschedulable ? 'btn-outline-primary' : 'btn-outline-secondary'}", form_class: "d-inline-block", disabled: !job_reschedulable, aria: { label: "Reschedule job" }, title: "Reschedule job" do %>
|
49
|
+
<%= button_to reschedule_job_path(job.id), method: :put, class: "btn btn-sm #{job_reschedulable ? 'btn-outline-primary' : 'btn-outline-secondary'}", form_class: "d-inline-block", disabled: !job_reschedulable, aria: { label: "Reschedule job" }, title: "Reschedule job", data: { confirm: "Confirm reschedule" } do %>
|
50
50
|
<%= render "good_job/shared/icons/skip_forward" %>
|
51
51
|
<% end %>
|
52
52
|
|
53
53
|
<% job_discardable = job.status.in? [:scheduled, :retried, :queued] %>
|
54
|
-
<%= button_to discard_job_path(job.id), method: :put, class: "btn btn-sm #{job_discardable ? 'btn-outline-primary' : 'btn-outline-secondary'}", form_class: "d-inline-block", disabled: !job_discardable, aria: { label: "Discard job" }, title: "Discard job" do %>
|
54
|
+
<%= button_to discard_job_path(job.id), method: :put, class: "btn btn-sm #{job_discardable ? 'btn-outline-primary' : 'btn-outline-secondary'}", form_class: "d-inline-block", disabled: !job_discardable, aria: { label: "Discard job" }, title: "Discard job", data: { confirm: "Confirm discard" } do %>
|
55
55
|
<%= render "good_job/shared/icons/stop" %>
|
56
56
|
<% end %>
|
57
57
|
|
58
|
-
<%= button_to retry_job_path(job.id), method: :put, class: "btn btn-sm #{job.status == :discarded ? 'btn-outline-primary' : 'btn-outline-secondary'}", form_class: "d-inline-block", disabled: job.status != :discarded, aria: { label: "Retry job" }, title: "Retry job" do %>
|
58
|
+
<%= button_to retry_job_path(job.id), method: :put, class: "btn btn-sm #{job.status == :discarded ? 'btn-outline-primary' : 'btn-outline-secondary'}", form_class: "d-inline-block", disabled: job.status != :discarded, aria: { label: "Retry job" }, title: "Retry job", data: { confirm: "Confirm retry" } do %>
|
59
59
|
<%= render "good_job/shared/icons/arrow_clockwise" %>
|
60
60
|
<% end %>
|
61
61
|
</div>
|
@@ -5,7 +5,7 @@
|
|
5
5
|
<%= render 'good_job/shared/filter', filter: @filter %>
|
6
6
|
|
7
7
|
<% if @filter.records.present? %>
|
8
|
-
<%= render 'good_job/
|
8
|
+
<%= render 'good_job/jobs/table', jobs: @filter.records %>
|
9
9
|
<nav aria-label="Job pagination" class="mt-3">
|
10
10
|
<ul class="pagination">
|
11
11
|
<li class="page-item">
|
@@ -1,3 +1,3 @@
|
|
1
|
-
<h1>ActiveJob ID: <code><%= @executions.first.id %></code></h1>
|
1
|
+
<h1 class="mb-3">ActiveJob ID: <code><%= @executions.first.id %></code></h1>
|
2
2
|
|
3
|
-
<%= render 'good_job/
|
3
|
+
<%= render 'good_job/executions/table', executions: @executions %>
|
@@ -1,16 +1,15 @@
|
|
1
1
|
<div class='card mb-2'>
|
2
2
|
<div class='card-body d-flex flex-wrap'>
|
3
|
-
|
4
3
|
<div class='me-4'>
|
5
4
|
<small>Filter by job class</small>
|
6
5
|
<br>
|
7
|
-
<%
|
6
|
+
<% filter.job_classes.each do |name, count| %>
|
8
7
|
<% if params[:job_class] == name %>
|
9
|
-
<%= link_to(
|
8
|
+
<%= link_to(filter.to_params(job_class: nil), class: 'btn btn-sm btn-outline-secondary active', role: "button", "aria-pressed": true) do %>
|
10
9
|
<%= name %> (<%= count %>)
|
11
10
|
<% end %>
|
12
11
|
<% else %>
|
13
|
-
<%= link_to(
|
12
|
+
<%= link_to(filter.to_params(job_class: name), class: 'btn btn-sm btn-outline-secondary', role: "button") do %>
|
14
13
|
<%= name %> (<%= count %>)
|
15
14
|
<% end %>
|
16
15
|
<% end %>
|
@@ -20,13 +19,13 @@
|
|
20
19
|
<div class='me-4'>
|
21
20
|
<small>Filter by state</small>
|
22
21
|
<br>
|
23
|
-
<%
|
22
|
+
<% filter.states.each do |name, count| %>
|
24
23
|
<% if params[:state] == name %>
|
25
|
-
<%= link_to(
|
24
|
+
<%= link_to(filter.to_params(state: nil), class: 'btn btn-sm btn-outline-secondary active', role: "button", "aria-pressed": true) do %>
|
26
25
|
<%= name %> (<%= count %>)
|
27
26
|
<% end %>
|
28
27
|
<% else %>
|
29
|
-
<%= link_to(
|
28
|
+
<%= link_to(filter.to_params(state: name), class: 'btn btn-sm btn-outline-secondary', role: "button") do %>
|
30
29
|
<%= name %> (<%= count %>)
|
31
30
|
<% end %>
|
32
31
|
<% end %>
|
@@ -36,13 +35,13 @@
|
|
36
35
|
<div>
|
37
36
|
<small>Filter by queue</small>
|
38
37
|
<br>
|
39
|
-
<%
|
38
|
+
<% filter.queues.each do |name, count| %>
|
40
39
|
<% if params[:queue_name] == name %>
|
41
|
-
<%= link_to(
|
40
|
+
<%= link_to(filter.to_params(queue_name: nil), class: 'btn btn-sm btn-outline-secondary active', role: "button", "aria-pressed": true) do %>
|
42
41
|
<%= name %> (<%= count %>)
|
43
42
|
<% end %>
|
44
43
|
<% else %>
|
45
|
-
<%= link_to(
|
44
|
+
<%= link_to(filter.to_params(queue_name: name), class: 'btn btn-sm btn-outline-secondary', role: "button") do %>
|
46
45
|
<%= name %> (<%= count %>)
|
47
46
|
<% end %>
|
48
47
|
<% end %>
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<!-- https://icons.getbootstrap.com/icons/play/ -->
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-play" viewBox="0 0 16 16">
|
3
|
+
<path d="M10.804 8 5 4.633v6.734L10.804 8zm.792-.696a.802.802 0 0 1 0 1.392l-6.363 3.692C4.713 12.69 4 12.345 4 11.692V4.308c0-.653.713-.998 1.233-.696l6.363 3.692z" />
|
4
|
+
</svg>
|
@@ -11,6 +11,7 @@
|
|
11
11
|
|
12
12
|
<%= javascript_include_tag bootstrap_path(format: :js, v: GoodJob::VERSION) %>
|
13
13
|
<%= javascript_include_tag chartist_path(format: :js, v: GoodJob::VERSION) %>
|
14
|
+
<%= javascript_include_tag rails_ujs_path(format: :js, v: GoodJob::VERSION) %>
|
14
15
|
</head>
|
15
16
|
<body>
|
16
17
|
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
@@ -29,7 +30,7 @@
|
|
29
30
|
<%= link_to "All Jobs", jobs_path, class: ["nav-link", ("active" if current_page?(jobs_path))] %>
|
30
31
|
</li>
|
31
32
|
<li class="nav-item">
|
32
|
-
<%= link_to "Cron Schedules",
|
33
|
+
<%= link_to "Cron Schedules", cron_entries_path, class: ["nav-link", ("active" if current_page?(cron_entries_path))] %>
|
33
34
|
</li>
|
34
35
|
<li class="nav-item">
|
35
36
|
<div class="nav-link">
|
data/engine/config/routes.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
GoodJob::Engine.routes.draw do
|
3
3
|
root to: 'executions#index'
|
4
|
-
|
4
|
+
|
5
|
+
resources :cron_entries, only: %i[index show] do
|
6
|
+
member do
|
7
|
+
post :enqueue
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
5
11
|
resources :jobs, only: %i[index show] do
|
6
12
|
member do
|
7
13
|
put :discard
|
@@ -20,6 +26,7 @@ GoodJob::Engine.routes.draw do
|
|
20
26
|
|
21
27
|
constraints(format: :js) do
|
22
28
|
get :bootstrap, action: :bootstrap_js
|
29
|
+
get :rails_ujs, action: :rails_ujs_js
|
23
30
|
get :chartist, action: :chartist_js
|
24
31
|
end
|
25
32
|
end
|
File without changes
|
@@ -157,7 +157,7 @@ module GoodJob
|
|
157
157
|
alias enable_cron? enable_cron
|
158
158
|
|
159
159
|
def cron
|
160
|
-
env_cron = JSON.parse(ENV['GOOD_JOB_CRON']) if ENV['GOOD_JOB_CRON'].present?
|
160
|
+
env_cron = JSON.parse(ENV['GOOD_JOB_CRON'], symbolize_names: true) if ENV['GOOD_JOB_CRON'].present?
|
161
161
|
|
162
162
|
options[:cron] ||
|
163
163
|
rails_config[:cron] ||
|
data/lib/good_job/cron_entry.rb
CHANGED
@@ -12,14 +12,29 @@ module GoodJob # :nodoc:
|
|
12
12
|
|
13
13
|
attr_reader :params
|
14
14
|
|
15
|
+
def self.all(configuration: nil)
|
16
|
+
configuration ||= GoodJob::Configuration.new({})
|
17
|
+
configuration.cron_entries
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.find(key, configuration: nil)
|
21
|
+
all(configuration: configuration).find { |entry| entry.key == key.to_sym }.tap do |cron_entry|
|
22
|
+
raise ActiveRecord::RecordNotFound unless cron_entry
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
15
26
|
def initialize(params = {})
|
16
|
-
@params = params
|
27
|
+
@params = params
|
28
|
+
|
29
|
+
raise ArgumentError, "Invalid cron format: '#{cron}'" unless fugit.instance_of?(Fugit::Cron)
|
17
30
|
end
|
18
31
|
|
19
32
|
def key
|
20
33
|
params.fetch(:key)
|
21
34
|
end
|
35
|
+
|
22
36
|
alias id key
|
37
|
+
alias to_param key
|
23
38
|
|
24
39
|
def job_class
|
25
40
|
params.fetch(:class)
|
@@ -42,16 +57,61 @@ module GoodJob # :nodoc:
|
|
42
57
|
end
|
43
58
|
|
44
59
|
def next_at
|
45
|
-
fugit = Fugit::Cron.parse(cron)
|
46
60
|
fugit.next_time.to_t
|
47
61
|
end
|
48
62
|
|
49
|
-
def
|
50
|
-
|
63
|
+
def schedule
|
64
|
+
fugit.original
|
65
|
+
end
|
66
|
+
|
67
|
+
def fugit
|
68
|
+
@_fugit ||= Fugit.parse(cron)
|
69
|
+
end
|
70
|
+
|
71
|
+
def jobs
|
72
|
+
GoodJob::ActiveJobJob.where(cron_key: key)
|
73
|
+
end
|
74
|
+
|
75
|
+
def last_at
|
76
|
+
return if last_job.blank?
|
77
|
+
|
78
|
+
if GoodJob::ActiveJobJob.column_names.include?('cron_at')
|
79
|
+
(last_job.cron_at || last_job.created_at).localtime
|
80
|
+
else
|
81
|
+
last_job.created_at
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def enqueue(cron_at = nil)
|
86
|
+
GoodJob::CurrentThread.within do |current_thread|
|
87
|
+
current_thread.cron_key = key
|
88
|
+
current_thread.cron_at = cron_at
|
89
|
+
|
90
|
+
job_class.constantize.set(set_value).perform_later(*args_value)
|
91
|
+
end
|
51
92
|
rescue ActiveRecord::RecordNotUnique
|
52
93
|
false
|
53
94
|
end
|
54
95
|
|
96
|
+
def last_job
|
97
|
+
if GoodJob::ActiveJobJob.column_names.include?('cron_at')
|
98
|
+
jobs.order("cron_at DESC NULLS LAST").first
|
99
|
+
else
|
100
|
+
jobs.order(created_at: :asc).last
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def display_properties
|
105
|
+
{
|
106
|
+
key: key,
|
107
|
+
class: job_class,
|
108
|
+
cron: schedule,
|
109
|
+
set: display_property(set),
|
110
|
+
args: display_property(args),
|
111
|
+
description: display_property(description),
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
55
115
|
private
|
56
116
|
|
57
117
|
def set_value
|
@@ -63,5 +123,16 @@ module GoodJob # :nodoc:
|
|
63
123
|
value = args || []
|
64
124
|
value.respond_to?(:call) ? value.call : value
|
65
125
|
end
|
126
|
+
|
127
|
+
def display_property(value)
|
128
|
+
case value
|
129
|
+
when NilClass
|
130
|
+
"None"
|
131
|
+
when Proc
|
132
|
+
"Lambda/Callable"
|
133
|
+
else
|
134
|
+
value
|
135
|
+
end
|
136
|
+
end
|
66
137
|
end
|
67
138
|
end
|
@@ -89,11 +89,7 @@ module GoodJob # :nodoc:
|
|
89
89
|
thr_scheduler.create_task(thr_cron_entry)
|
90
90
|
|
91
91
|
Rails.application.executor.wrap do
|
92
|
-
|
93
|
-
CurrentThread.cron_key = thr_cron_entry.key
|
94
|
-
CurrentThread.cron_at = thr_cron_at
|
95
|
-
|
96
|
-
cron_entry.enqueue
|
92
|
+
cron_entry.enqueue(thr_cron_at)
|
97
93
|
end
|
98
94
|
end
|
99
95
|
|
@@ -5,6 +5,15 @@ module GoodJob
|
|
5
5
|
# Thread-local attributes for passing values from Instrumentation.
|
6
6
|
# (Cannot use ActiveSupport::CurrentAttributes because ActiveJob resets it)
|
7
7
|
module CurrentThread
|
8
|
+
# Resettable accessors for thread-local values.
|
9
|
+
ACCESSORS = %i[
|
10
|
+
cron_at
|
11
|
+
cron_key
|
12
|
+
error_on_discard
|
13
|
+
error_on_retry
|
14
|
+
execution
|
15
|
+
].freeze
|
16
|
+
|
8
17
|
# @!attribute [rw] cron_at
|
9
18
|
# @!scope class
|
10
19
|
# Cron At
|
@@ -36,13 +45,20 @@ module GoodJob
|
|
36
45
|
thread_mattr_accessor :execution
|
37
46
|
|
38
47
|
# Resets attributes
|
48
|
+
# @param [Hash] values to assign
|
39
49
|
# @return [void]
|
40
|
-
def self.reset
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
50
|
+
def self.reset(values = {})
|
51
|
+
ACCESSORS.each do |accessor|
|
52
|
+
send("#{accessor}=", values[accessor])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Exports values to hash
|
57
|
+
# @return [Hash]
|
58
|
+
def self.to_h
|
59
|
+
ACCESSORS.each_with_object({}) do |accessor, hash|
|
60
|
+
hash[accessor] = send(accessor)
|
61
|
+
end
|
46
62
|
end
|
47
63
|
|
48
64
|
# @return [String] UUID of the currently executing GoodJob::Execution
|
@@ -60,12 +76,14 @@ module GoodJob
|
|
60
76
|
(Thread.current.name || Thread.current.object_id).to_s
|
61
77
|
end
|
62
78
|
|
79
|
+
# Wrap the yielded block with CurrentThread values and reset after the block
|
80
|
+
# @yield [self]
|
63
81
|
# @return [void]
|
64
82
|
def self.within
|
65
|
-
|
83
|
+
original_values = to_h
|
66
84
|
yield(self)
|
67
85
|
ensure
|
68
|
-
reset
|
86
|
+
reset(original_values)
|
69
87
|
end
|
70
88
|
end
|
71
89
|
end
|
data/lib/good_job/execution.rb
CHANGED
@@ -309,22 +309,24 @@ module GoodJob
|
|
309
309
|
|
310
310
|
# @return [ExecutionResult]
|
311
311
|
def execute
|
312
|
-
GoodJob::CurrentThread.
|
313
|
-
|
312
|
+
GoodJob::CurrentThread.within do |current_thread|
|
313
|
+
current_thread.reset
|
314
|
+
current_thread.execution = self
|
314
315
|
|
315
|
-
|
316
|
-
|
317
|
-
|
316
|
+
# DEPRECATION: Remove deprecated `good_job:` parameter in GoodJob v3
|
317
|
+
ActiveSupport::Notifications.instrument("perform_job.good_job", { good_job: self, execution: self, process_id: current_thread.process_id, thread_name: current_thread.thread_name }) do
|
318
|
+
value = ActiveJob::Base.execute(active_job_data)
|
318
319
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
320
|
+
if value.is_a?(Exception)
|
321
|
+
handled_error = value
|
322
|
+
value = nil
|
323
|
+
end
|
324
|
+
handled_error ||= current_thread.error_on_retry || current_thread.error_on_discard
|
324
325
|
|
325
|
-
|
326
|
-
|
327
|
-
|
326
|
+
ExecutionResult.new(value: value, handled_error: handled_error)
|
327
|
+
rescue StandardError => e
|
328
|
+
ExecutionResult.new(value: nil, unhandled_error: e)
|
329
|
+
end
|
328
330
|
end
|
329
331
|
end
|
330
332
|
end
|
data/lib/good_job/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: good_job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Sheldon
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-10-
|
11
|
+
date: 2021-10-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -126,16 +126,16 @@ dependencies:
|
|
126
126
|
name: capybara
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
|
-
- - "
|
129
|
+
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version:
|
131
|
+
version: 3.35.0
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
|
-
- - "
|
136
|
+
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
138
|
+
version: 3.35.0
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: database_cleaner
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -351,27 +351,29 @@ files:
|
|
351
351
|
- engine/app/assets/vendor/bootstrap/bootstrap.min.css
|
352
352
|
- engine/app/assets/vendor/chartist/chartist.css
|
353
353
|
- engine/app/assets/vendor/chartist/chartist.js
|
354
|
+
- engine/app/assets/vendor/rails_ujs.js
|
354
355
|
- engine/app/controllers/good_job/assets_controller.rb
|
355
356
|
- engine/app/controllers/good_job/base_controller.rb
|
356
|
-
- engine/app/controllers/good_job/
|
357
|
+
- engine/app/controllers/good_job/cron_entries_controller.rb
|
357
358
|
- engine/app/controllers/good_job/executions_controller.rb
|
358
359
|
- engine/app/controllers/good_job/jobs_controller.rb
|
359
360
|
- engine/app/filters/good_job/base_filter.rb
|
360
361
|
- engine/app/filters/good_job/executions_filter.rb
|
361
362
|
- engine/app/filters/good_job/jobs_filter.rb
|
362
363
|
- engine/app/helpers/good_job/application_helper.rb
|
363
|
-
- engine/app/
|
364
|
-
- engine/app/views/good_job/
|
364
|
+
- engine/app/views/good_job/cron_entries/index.html.erb
|
365
|
+
- engine/app/views/good_job/cron_entries/show.html.erb
|
366
|
+
- engine/app/views/good_job/executions/_table.erb
|
365
367
|
- engine/app/views/good_job/executions/index.html.erb
|
368
|
+
- engine/app/views/good_job/jobs/_table.erb
|
366
369
|
- engine/app/views/good_job/jobs/index.html.erb
|
367
370
|
- engine/app/views/good_job/jobs/show.html.erb
|
368
371
|
- engine/app/views/good_job/shared/_chart.erb
|
369
|
-
- engine/app/views/good_job/shared/_executions_table.erb
|
370
372
|
- engine/app/views/good_job/shared/_filter.erb
|
371
|
-
- engine/app/views/good_job/shared/_jobs_table.erb
|
372
373
|
- engine/app/views/good_job/shared/icons/_arrow_clockwise.html.erb
|
373
374
|
- engine/app/views/good_job/shared/icons/_check.html.erb
|
374
375
|
- engine/app/views/good_job/shared/icons/_exclamation.html.erb
|
376
|
+
- engine/app/views/good_job/shared/icons/_play.html.erb
|
375
377
|
- engine/app/views/good_job/shared/icons/_skip_forward.html.erb
|
376
378
|
- engine/app/views/good_job/shared/icons/_stop.html.erb
|
377
379
|
- engine/app/views/good_job/shared/icons/_trash.html.erb
|
@@ -389,6 +391,7 @@ files:
|
|
389
391
|
- lib/good_job.rb
|
390
392
|
- lib/good_job/active_job_extensions.rb
|
391
393
|
- lib/good_job/active_job_extensions/concurrency.rb
|
394
|
+
- lib/good_job/active_job_job.rb
|
392
395
|
- lib/good_job/adapter.rb
|
393
396
|
- lib/good_job/cli.rb
|
394
397
|
- lib/good_job/configuration.rb
|