good_job 3.99.0 → 4.0.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 +4 -4
- data/CHANGELOG.md +21 -0
- data/app/charts/good_job/scheduled_by_queue_chart.rb +2 -2
- data/app/controllers/good_job/cron_entries_controller.rb +0 -8
- data/app/controllers/good_job/metrics_controller.rb +1 -1
- data/app/controllers/good_job/performance_controller.rb +19 -0
- data/app/models/concerns/good_job/filterable.rb +1 -1
- data/app/models/good_job/base_execution.rb +104 -201
- data/app/models/good_job/cron_entry.rb +0 -2
- data/app/models/good_job/discrete_execution.rb +1 -31
- data/app/models/good_job/execution.rb +3 -7
- data/app/models/good_job/job.rb +37 -116
- data/app/models/good_job/process.rb +7 -20
- data/app/views/good_job/batches/index.html.erb +11 -15
- data/app/views/good_job/jobs/_executions.erb +1 -1
- data/app/views/good_job/jobs/_table.erb +1 -1
- data/app/views/good_job/jobs/show.html.erb +1 -8
- data/app/views/good_job/performance/index.html.erb +43 -0
- data/app/views/good_job/shared/_navbar.erb +2 -2
- data/config/locales/de.yml +4 -7
- data/config/locales/en.yml +4 -7
- data/config/locales/es.yml +4 -7
- data/config/locales/fr.yml +4 -7
- data/config/locales/it.yml +4 -7
- data/config/locales/ja.yml +4 -7
- data/config/locales/ko.yml +4 -7
- data/config/locales/nl.yml +4 -7
- data/config/locales/pt-BR.yml +4 -7
- data/config/locales/ru.yml +4 -7
- data/config/locales/tr.yml +4 -7
- data/config/locales/uk.yml +4 -7
- data/config/routes.rb +1 -1
- data/lib/generators/good_job/templates/update/migrations/01_create_good_jobs.rb.erb +65 -3
- data/lib/good_job/active_job_extensions/batches.rb +1 -1
- data/lib/good_job/active_job_extensions/concurrency.rb +10 -10
- data/lib/good_job/adapter.rb +13 -24
- data/lib/good_job/configuration.rb +5 -1
- data/lib/good_job/current_thread.rb +6 -6
- data/lib/good_job/job_performer.rb +2 -2
- data/lib/good_job/log_subscriber.rb +2 -10
- data/lib/good_job/notifier.rb +3 -3
- data/lib/good_job/version.rb +1 -1
- data/lib/good_job.rb +16 -21
- metadata +18 -32
- data/app/controllers/good_job/performances_controller.rb +0 -23
- data/app/views/good_job/performances/show.html.erb +0 -50
- data/lib/generators/good_job/templates/update/migrations/02_create_good_job_settings.rb.erb +0 -20
- data/lib/generators/good_job/templates/update/migrations/03_create_index_good_jobs_jobs_on_priority_created_at_when_unfinished.rb.erb +0 -19
- data/lib/generators/good_job/templates/update/migrations/04_create_good_job_batches.rb.erb +0 -35
- data/lib/generators/good_job/templates/update/migrations/05_create_good_job_executions.rb.erb +0 -33
- data/lib/generators/good_job/templates/update/migrations/06_create_good_jobs_error_event.rb.erb +0 -16
- data/lib/generators/good_job/templates/update/migrations/07_recreate_good_job_cron_indexes_with_conditional.rb.erb +0 -45
- data/lib/generators/good_job/templates/update/migrations/08_create_good_job_labels.rb.erb +0 -15
- data/lib/generators/good_job/templates/update/migrations/09_create_good_job_labels_index.rb.erb +0 -22
- data/lib/generators/good_job/templates/update/migrations/10_remove_good_job_active_id_index.rb.erb +0 -21
- data/lib/generators/good_job/templates/update/migrations/11_create_index_good_job_jobs_for_candidate_lookup.rb.erb +0 -19
- data/lib/generators/good_job/templates/update/migrations/12_create_good_job_execution_error_backtrace.rb.erb +0 -15
- data/lib/generators/good_job/templates/update/migrations/13_create_good_job_process_lock_ids.rb.erb +0 -18
- data/lib/generators/good_job/templates/update/migrations/14_create_good_job_process_lock_indexes.rb.erb +0 -38
- data/lib/generators/good_job/templates/update/migrations/15_create_good_job_execution_duration.rb.erb +0 -15
data/app/models/good_job/job.rb
CHANGED
@@ -2,10 +2,6 @@
|
|
2
2
|
|
3
3
|
module GoodJob
|
4
4
|
# Active Record model that represents an +ActiveJob+ job.
|
5
|
-
# There is not a table in the database whose discrete rows represents "Jobs".
|
6
|
-
# The +good_jobs+ table is a table of individual {GoodJob::Execution}s that share the same +active_job_id+.
|
7
|
-
# A single row from the +good_jobs+ table of executions is fetched to represent a Job.
|
8
|
-
#
|
9
5
|
class Job < BaseExecution
|
10
6
|
# Raised when an inappropriate action is applied to a Job based on its state.
|
11
7
|
ActionForStateMismatchError = Class.new(StandardError)
|
@@ -16,29 +12,17 @@ module GoodJob
|
|
16
12
|
# Raised when Active Job data cannot be deserialized
|
17
13
|
ActiveJobDeserializationError = Class.new(StandardError)
|
18
14
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
def table_name=(_value)
|
23
|
-
raise NotImplementedError, 'Assign GoodJob::Execution.table_name directly'
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
self.primary_key = 'active_job_id'
|
28
|
-
self.advisory_lockable_column = 'active_job_id'
|
15
|
+
self.table_name = 'good_jobs'
|
16
|
+
self.advisory_lockable_column = 'id'
|
29
17
|
self.implicit_order_column = 'created_at'
|
30
18
|
|
31
19
|
belongs_to :batch, class_name: 'GoodJob::BatchRecord', inverse_of: :jobs, optional: true
|
32
20
|
belongs_to :locked_by_process, class_name: "GoodJob::Process", foreign_key: :locked_by_id, inverse_of: :locked_jobs, optional: true
|
33
|
-
has_many :executions, -> { order(created_at: :asc) }, class_name: 'GoodJob::Execution', foreign_key: 'active_job_id', inverse_of: :job
|
34
|
-
|
21
|
+
has_many :executions, -> { order(created_at: :asc) }, class_name: 'GoodJob::Execution', foreign_key: 'active_job_id', primary_key: :active_job_id, inverse_of: :job, dependent: :delete_all
|
22
|
+
# TODO: rename callers of discrete_execution to executions, but after v4 has some time to bake for cleaner diffs/patches
|
23
|
+
has_many :discrete_executions, -> { order(created_at: :asc) }, class_name: 'GoodJob::Execution', foreign_key: 'active_job_id', primary_key: :active_job_id, inverse_of: :job, dependent: :delete_all
|
35
24
|
|
36
|
-
|
37
|
-
GoodJob::DiscreteExecution.where(active_job_id: active_job_id).delete_all if discrete? # TODO: move into association `dependent: :delete_all` after v4
|
38
|
-
}
|
39
|
-
|
40
|
-
# Only the most-recent unretried execution represents a "Job"
|
41
|
-
default_scope { where(retried_good_job_id: nil) }
|
25
|
+
before_create -> { self.id = active_job_id }, if: -> { active_job_id.present? }
|
42
26
|
|
43
27
|
# Get Jobs finished before the given timestamp.
|
44
28
|
# @!method finished_before(timestamp)
|
@@ -64,65 +48,11 @@ module GoodJob
|
|
64
48
|
|
65
49
|
scope :unfinished_undiscrete, -> { where(finished_at: nil, retried_good_job_id: nil, is_discrete: [nil, false]) }
|
66
50
|
|
67
|
-
#
|
68
|
-
#
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
# Override #reload to add a custom scope to ensure the reloaded record is the head execution
|
74
|
-
# @return [Job]
|
75
|
-
def reload(options = nil)
|
76
|
-
self.class.connection.clear_query_cache
|
77
|
-
|
78
|
-
# override with the `where(retried_good_job_id: nil)` scope
|
79
|
-
override_query = self.class.where(retried_good_job_id: nil)
|
80
|
-
fresh_object =
|
81
|
-
if options && options[:lock]
|
82
|
-
self.class.unscoped { override_query.lock(options[:lock]).find(id) }
|
83
|
-
else
|
84
|
-
self.class.unscoped { override_query.find(id) }
|
85
|
-
end
|
86
|
-
|
87
|
-
@attributes = fresh_object.instance_variable_get(:@attributes)
|
88
|
-
@new_record = false
|
89
|
-
@previously_new_record = false
|
90
|
-
self
|
91
|
-
end
|
92
|
-
|
93
|
-
# This job's most recent {Execution}
|
94
|
-
# @param reload [Booelan] whether to reload executions
|
95
|
-
# @return [Execution]
|
96
|
-
def head_execution(reload: false)
|
97
|
-
executions.reload if reload
|
98
|
-
executions.load # memoize the results
|
99
|
-
executions.last
|
100
|
-
end
|
101
|
-
|
102
|
-
# This job's initial/oldest {Execution}
|
103
|
-
# @return [Execution]
|
104
|
-
def tail_execution
|
105
|
-
executions.first
|
106
|
-
end
|
107
|
-
|
108
|
-
# The number of times this job has been executed, according to Active Job's serialized state.
|
109
|
-
# @return [Numeric]
|
110
|
-
def executions_count
|
111
|
-
aj_count = serialized_params.fetch('executions', 0)
|
112
|
-
# The execution count within serialized_params is not updated
|
113
|
-
# once the underlying execution has been executed.
|
114
|
-
if status.in? [:discarded, :succeeded, :running]
|
115
|
-
aj_count + 1
|
116
|
-
else
|
117
|
-
aj_count
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
# The number of times this job has been executed, according to the number of GoodJob {Execution} records.
|
122
|
-
# @return [Numeric]
|
123
|
-
def preserved_executions_count
|
124
|
-
executions.size
|
125
|
-
end
|
51
|
+
# TODO: it would be nice to enforce these values at the model
|
52
|
+
# validates :active_job_id, presence: true
|
53
|
+
# validates :scheduled_at, presence: true
|
54
|
+
# validates :job_class, presence: true
|
55
|
+
# validates :error_event, presence: true, if: -> { error.present? }
|
126
56
|
|
127
57
|
# The most recent error message.
|
128
58
|
# If the job has been retried, the error will be fetched from the previous {Execution} record.
|
@@ -155,6 +85,10 @@ module GoodJob
|
|
155
85
|
job_class
|
156
86
|
end
|
157
87
|
|
88
|
+
def executions_count
|
89
|
+
super || 0
|
90
|
+
end
|
91
|
+
|
158
92
|
# Tests whether the job is being executed right now.
|
159
93
|
# @return [Boolean]
|
160
94
|
def running?
|
@@ -189,33 +123,33 @@ module GoodJob
|
|
189
123
|
# @return [ActiveJob::Base]
|
190
124
|
def retry_job
|
191
125
|
with_advisory_lock do
|
192
|
-
|
193
|
-
active_job =
|
126
|
+
reload
|
127
|
+
active_job = self.active_job(ignore_deserialization_errors: true)
|
194
128
|
|
195
129
|
raise ActiveJobDeserializationError if active_job.nil?
|
196
130
|
raise AdapterNotGoodJobError unless active_job.class.queue_adapter.is_a? GoodJob::Adapter
|
197
|
-
raise ActionForStateMismatchError if
|
131
|
+
raise ActionForStateMismatchError if finished_at.blank? || error.blank?
|
198
132
|
|
199
133
|
# Update the executions count because the previous execution will not have been preserved
|
200
134
|
# Do not update `exception_executions` because that comes from rescue_from's arguments
|
201
135
|
active_job.executions = (active_job.executions || 0) + 1
|
202
136
|
|
203
137
|
begin
|
204
|
-
error_class, error_message =
|
138
|
+
error_class, error_message = error.split(ERROR_MESSAGE_SEPARATOR).map(&:strip)
|
205
139
|
error = error_class.constantize.new(error_message)
|
206
140
|
rescue StandardError
|
207
|
-
error = StandardError.new(
|
141
|
+
error = StandardError.new(error)
|
208
142
|
end
|
209
143
|
|
210
144
|
new_active_job = nil
|
211
145
|
GoodJob::CurrentThread.within do |current_thread|
|
212
|
-
current_thread.
|
146
|
+
current_thread.job = self
|
213
147
|
current_thread.retry_now = true
|
214
148
|
|
215
|
-
|
149
|
+
self.class.transaction(joinable: false, requires_new: true) do
|
216
150
|
new_active_job = active_job.retry_job(wait: 0, error: error)
|
217
|
-
|
218
|
-
|
151
|
+
self.error_event = ERROR_EVENT_RETRIED if error
|
152
|
+
save!
|
219
153
|
end
|
220
154
|
end
|
221
155
|
|
@@ -244,11 +178,10 @@ module GoodJob
|
|
244
178
|
# @return [void]
|
245
179
|
def reschedule_job(scheduled_at = Time.current)
|
246
180
|
with_advisory_lock do
|
247
|
-
|
248
|
-
|
249
|
-
raise ActionForStateMismatchError if execution.finished_at.present?
|
181
|
+
reload
|
182
|
+
raise ActionForStateMismatchError if finished_at.present?
|
250
183
|
|
251
|
-
|
184
|
+
update(scheduled_at: scheduled_at)
|
252
185
|
end
|
253
186
|
end
|
254
187
|
|
@@ -256,9 +189,7 @@ module GoodJob
|
|
256
189
|
# @return [void]
|
257
190
|
def destroy_job
|
258
191
|
with_advisory_lock do
|
259
|
-
|
260
|
-
|
261
|
-
raise ActionForStateMismatchError if execution.finished_at.blank?
|
192
|
+
raise ActionForStateMismatchError if finished_at.blank?
|
262
193
|
|
263
194
|
destroy
|
264
195
|
end
|
@@ -270,37 +201,27 @@ module GoodJob
|
|
270
201
|
attributes['id']
|
271
202
|
end
|
272
203
|
|
273
|
-
# Utility method to test whether this job's underlying attributes represents its most recent execution.
|
274
|
-
# @return [Boolean]
|
275
|
-
def _head?
|
276
|
-
_execution_id == head_execution(reload: true).id
|
277
|
-
end
|
278
|
-
|
279
204
|
private
|
280
205
|
|
281
206
|
def _discard_job(message)
|
282
|
-
|
283
|
-
active_job = execution.active_job(ignore_deserialization_errors: true)
|
207
|
+
active_job = self.active_job(ignore_deserialization_errors: true)
|
284
208
|
|
285
|
-
raise ActionForStateMismatchError if
|
209
|
+
raise ActionForStateMismatchError if finished_at.present?
|
286
210
|
|
287
211
|
job_error = GoodJob::Job::DiscardJobError.new(message)
|
288
212
|
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
}.tap do |attrs|
|
295
|
-
attrs[:error_event] = ERROR_EVENT_DISCARDED if self.class.error_event_migrated?
|
296
|
-
end
|
213
|
+
update_record = proc do
|
214
|
+
update(
|
215
|
+
finished_at: Time.current,
|
216
|
+
error: self.class.format_error(job_error),
|
217
|
+
error_event: ERROR_EVENT_DISCARDED
|
297
218
|
)
|
298
219
|
end
|
299
220
|
|
300
221
|
if active_job.respond_to?(:instrument)
|
301
|
-
active_job.send :instrument, :discard, error: job_error, &
|
222
|
+
active_job.send :instrument, :discard, error: job_error, &update_record
|
302
223
|
else
|
303
|
-
|
224
|
+
update_record.call
|
304
225
|
end
|
305
226
|
end
|
306
227
|
end
|
@@ -33,13 +33,9 @@ module GoodJob # :nodoc:
|
|
33
33
|
# @!scope class
|
34
34
|
# @return [ActiveRecord::Relation]
|
35
35
|
scope :active, (lambda do
|
36
|
-
|
37
|
-
|
38
|
-
query.where(lock_type:
|
39
|
-
.or(query.where(lock_type: nil).where(arel_table[:updated_at].gt(EXPIRED_INTERVAL.ago)))
|
40
|
-
else
|
41
|
-
advisory_locked
|
42
|
-
end
|
36
|
+
query = joins_advisory_locks
|
37
|
+
query.where(lock_type: LOCK_TYPE_ENUMS[LOCK_TYPE_ADVISORY]).advisory_locked
|
38
|
+
.or(query.where(lock_type: nil).where(arel_table[:updated_at].gt(EXPIRED_INTERVAL.ago)))
|
43
39
|
end)
|
44
40
|
|
45
41
|
# Processes that are inactive and unlocked (e.g. SIGKILLed)
|
@@ -47,13 +43,9 @@ module GoodJob # :nodoc:
|
|
47
43
|
# @!scope class
|
48
44
|
# @return [ActiveRecord::Relation]
|
49
45
|
scope :inactive, (lambda do
|
50
|
-
|
51
|
-
|
52
|
-
query.where(lock_type:
|
53
|
-
.or(query.where(lock_type: nil).where(arel_table[:updated_at].lt(EXPIRED_INTERVAL.ago)))
|
54
|
-
else
|
55
|
-
advisory_unlocked
|
56
|
-
end
|
46
|
+
query = joins_advisory_locks
|
47
|
+
query.where(lock_type: LOCK_TYPE_ENUMS[LOCK_TYPE_ADVISORY]).advisory_unlocked
|
48
|
+
.or(query.where(lock_type: nil).where(arel_table[:updated_at].lt(EXPIRED_INTERVAL.ago)))
|
57
49
|
end)
|
58
50
|
|
59
51
|
# Deletes all inactive process records.
|
@@ -64,11 +56,6 @@ module GoodJob # :nodoc:
|
|
64
56
|
end
|
65
57
|
end
|
66
58
|
|
67
|
-
# @return [Boolean]
|
68
|
-
def self.lock_type_migrated?
|
69
|
-
columns_hash["lock_type"].present?
|
70
|
-
end
|
71
|
-
|
72
59
|
def self.create_record(id:, with_advisory_lock: false)
|
73
60
|
attributes = {
|
74
61
|
id: id,
|
@@ -76,7 +63,7 @@ module GoodJob # :nodoc:
|
|
76
63
|
}
|
77
64
|
if with_advisory_lock
|
78
65
|
attributes[:create_with_advisory_lock] = true
|
79
|
-
attributes[:lock_type] = LOCK_TYPE_ADVISORY
|
66
|
+
attributes[:lock_type] = LOCK_TYPE_ADVISORY
|
80
67
|
end
|
81
68
|
create!(attributes)
|
82
69
|
end
|
@@ -2,19 +2,15 @@
|
|
2
2
|
<h2 class="pt-3 pb-2"><%= t ".title" %></h2>
|
3
3
|
</div>
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
<
|
9
|
-
<
|
10
|
-
|
11
|
-
<%=
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
</nav>
|
17
|
-
<% end %>
|
18
|
-
<% else %>
|
19
|
-
<h3 class="text-center my-5"><%= t ".pending_migrations" %></h3>
|
5
|
+
<%= render 'good_job/batches/table', batches: @filter.records, filter: @filter %>
|
6
|
+
<% if @filter.records.present? %>
|
7
|
+
<nav aria-label="Batch pagination" class="mt-3">
|
8
|
+
<ul class="pagination">
|
9
|
+
<li class="page-item">
|
10
|
+
<%= link_to(@filter.to_params(after_created_at: @filter.last.created_at, after_id: @filter.last.id), class: "page-link") do %>
|
11
|
+
<%= t ".older_batches" %> <span aria-hidden="true">»</span>
|
12
|
+
<% end %>
|
13
|
+
</li>
|
14
|
+
</ul>
|
15
|
+
</nav>
|
20
16
|
<% end %>
|
@@ -38,7 +38,7 @@
|
|
38
38
|
<strong class="small text-danger"><%= t "good_job.shared.error" %>:</strong>
|
39
39
|
<code class="text-wrap text-break m-0 text-secondary-emphasis"><%= execution.error %></code>
|
40
40
|
</div>
|
41
|
-
<% if
|
41
|
+
<% if execution.error_backtrace&.any? %>
|
42
42
|
<%= tag.ul class: "nav nav-tabs small w-fit-content", id: dom_id(execution, :tab), role: "tablist" do %>
|
43
43
|
<li class="nav-item" role="presentation">
|
44
44
|
<%= tag.button t(".application_trace"), class: "nav-link active p-1", id: dom_id(execution, :application), data: { bs_toggle: "tab", bs_target: dom_id(execution, :"#application_pane") }, type: "button", role: "tab", aria: { controls: dom_id(execution, :application_pane), selected: true } %>
|
@@ -102,7 +102,7 @@
|
|
102
102
|
<%= tag.span relative_time(job.last_status_at), class: "small mt-1" %>
|
103
103
|
<div>
|
104
104
|
<%= status_badge job.status %>
|
105
|
-
<% if job.status == :discarded && job.
|
105
|
+
<% if job.status == :discarded && job.error_event %>
|
106
106
|
<div class="text-black text-center">
|
107
107
|
<small><%= t(job.error_event, scope: 'good_job.error_event') %></small>
|
108
108
|
</div>
|
@@ -5,9 +5,6 @@
|
|
5
5
|
<li class="breadcrumb-item"><%= link_to t(".jobs"), jobs_path %></li>
|
6
6
|
<li class="breadcrumb-item active" aria-current="page">
|
7
7
|
<%= tag.code @job.id, class: "text-muted" %>
|
8
|
-
<% if @job.discrete? %>
|
9
|
-
<span class="badge bg-info">Discrete</span>
|
10
|
-
<% end %>
|
11
8
|
</li>
|
12
9
|
</ol>
|
13
10
|
</nav>
|
@@ -87,8 +84,4 @@
|
|
87
84
|
<%= tag.pre JSON.pretty_generate(@job.display_serialized_params) %>
|
88
85
|
<% end %>
|
89
86
|
|
90
|
-
|
91
|
-
<%= render 'executions', executions: @job.discrete_executions.reverse %>
|
92
|
-
<% else %>
|
93
|
-
<%= render 'executions', executions: @job.executions.includes_advisory_locks.reverse %>
|
94
|
-
<% end %>
|
87
|
+
<%= render 'executions', executions: @job.executions.reverse %>
|
@@ -0,0 +1,43 @@
|
|
1
|
+
<div class="border-bottom">
|
2
|
+
<h2 class="pt-3 pb-2"><%= t ".title" %></h2>
|
3
|
+
</div>
|
4
|
+
|
5
|
+
<div class="my-3 card">
|
6
|
+
<div class="list-group list-group-flush text-nowrap" role="table">
|
7
|
+
<header class="list-group-item bg-body-tertiary">
|
8
|
+
<div class="row small text-muted text-uppercase align-items-center">
|
9
|
+
<div class="col-12 col-lg-4"><%= t ".job_class" %></div>
|
10
|
+
<div class="col-lg-2 d-none d-lg-block"><%= t ".executions" %></div>
|
11
|
+
|
12
|
+
<div class="col-lg-2 d-none d-lg-block"><%= t ".average_duration" %></div>
|
13
|
+
<div class="col-lg-2 d-none d-lg-block"><%= t ".minimum_duration" %></div>
|
14
|
+
<div class="col-lg-2 d-none d-lg-block"><%= t ".maximum_duration" %></div>
|
15
|
+
</div>
|
16
|
+
</header>
|
17
|
+
|
18
|
+
<% @performances.each do |performance| %>
|
19
|
+
<div role="row" class="list-group-item py-3">
|
20
|
+
<div class="row align-items-center">
|
21
|
+
<div class="col-12 col-lg-4"><%= performance.job_class %></div>
|
22
|
+
<div class="col-6 col-lg-2 text-wrap">
|
23
|
+
<div class="d-lg-none small text-muted mt-1"><%= t ".executions" %></div>
|
24
|
+
<%= performance.executions_count %>
|
25
|
+
</div>
|
26
|
+
|
27
|
+
<div class="col-6 col-lg-2 text-wrap">
|
28
|
+
<div class="d-lg-none small text-muted mt-1"><%= t ".average_duration" %></div>
|
29
|
+
<%= format_duration performance.avg_duration %>
|
30
|
+
</div>
|
31
|
+
<div class="col-6 col-lg-2 text-wrap">
|
32
|
+
<div class="d-lg-none small text-muted mt-1"><%= t ".minimum_duration" %></div>
|
33
|
+
<%= format_duration performance.min_duration %>
|
34
|
+
</div>
|
35
|
+
<div class="col-6 col-lg-2 text-wrap">
|
36
|
+
<div class="d-lg-none small text-muted mt-1"><%= t ".maximum_duration" %></div>
|
37
|
+
<%= format_duration performance.max_duration %>
|
38
|
+
</div>
|
39
|
+
</div>
|
40
|
+
</div>
|
41
|
+
<% end %>
|
42
|
+
</div>
|
43
|
+
</div>
|
@@ -40,8 +40,8 @@
|
|
40
40
|
<% end %>
|
41
41
|
</li>
|
42
42
|
<li class="nav-item">
|
43
|
-
<%= link_to
|
44
|
-
<%= t(".
|
43
|
+
<%= link_to performance_index_path, class: ["nav-link", ("active" if controller_name == 'performance')] do %>
|
44
|
+
<%= t(".performance") %>
|
45
45
|
<% end %>
|
46
46
|
</li>
|
47
47
|
</ul>
|
data/config/locales/de.yml
CHANGED
@@ -11,7 +11,6 @@ de:
|
|
11
11
|
batches:
|
12
12
|
index:
|
13
13
|
older_batches: Ältere Chargen
|
14
|
-
pending_migrations: GoodJob hat ausstehende Datenbankmigrationen.
|
15
14
|
title: Chargen
|
16
15
|
jobs:
|
17
16
|
actions:
|
@@ -48,7 +47,6 @@ de:
|
|
48
47
|
index:
|
49
48
|
no_cron_schedules_found: Keine Cron-Zeitpläne gefunden.
|
50
49
|
title: Cron-Zeitpläne
|
51
|
-
pending_migrations: Erfordert ausstehende GoodJob-Datenbankmigration.
|
52
50
|
show:
|
53
51
|
cron_entry_key: Cron-Eingabetaste
|
54
52
|
datetime:
|
@@ -196,8 +194,8 @@ de:
|
|
196
194
|
thousand: K
|
197
195
|
trillion: T
|
198
196
|
unit: ''
|
199
|
-
|
200
|
-
|
197
|
+
performance:
|
198
|
+
index:
|
201
199
|
average_duration: Durchschnittliche Dauer
|
202
200
|
executions: Hinrichtungen
|
203
201
|
job_class: Berufsklasse
|
@@ -233,13 +231,14 @@ de:
|
|
233
231
|
jobs: Jobs
|
234
232
|
live_poll: Live Poll
|
235
233
|
name: "GoodJob 👍"
|
236
|
-
|
234
|
+
performance: Leistung
|
237
235
|
processes: Prozesse
|
238
236
|
theme:
|
239
237
|
auto: Auto
|
240
238
|
dark: Dunkel
|
241
239
|
light: Licht
|
242
240
|
theme: Thema
|
241
|
+
pending_migrations: GoodJob hat ausstehende Datenbankmigrationen.
|
243
242
|
secondary_navbar:
|
244
243
|
inspiration: Denk daran, auch du machst einen guten Job!
|
245
244
|
last_updated: Zuletzt aktualisiert
|
@@ -250,5 +249,3 @@ de:
|
|
250
249
|
running: Laufend
|
251
250
|
scheduled: Geplant
|
252
251
|
succeeded: Erfolgreich
|
253
|
-
shared:
|
254
|
-
needs_migration: Bitte führen Sie GoodJob-Migrationen aus.
|
data/config/locales/en.yml
CHANGED
@@ -11,7 +11,6 @@ en:
|
|
11
11
|
batches:
|
12
12
|
index:
|
13
13
|
older_batches: Older batches
|
14
|
-
pending_migrations: GoodJob has pending database migrations.
|
15
14
|
title: Batches
|
16
15
|
jobs:
|
17
16
|
actions:
|
@@ -48,7 +47,6 @@ en:
|
|
48
47
|
index:
|
49
48
|
no_cron_schedules_found: No cron schedules found.
|
50
49
|
title: Cron Schedules
|
51
|
-
pending_migrations: Requires pending GoodJob database migration.
|
52
50
|
show:
|
53
51
|
cron_entry_key: Cron Entry Key
|
54
52
|
datetime:
|
@@ -196,8 +194,8 @@ en:
|
|
196
194
|
thousand: K
|
197
195
|
trillion: T
|
198
196
|
unit: ''
|
199
|
-
|
200
|
-
|
197
|
+
performance:
|
198
|
+
index:
|
201
199
|
average_duration: Average duration
|
202
200
|
executions: Executions
|
203
201
|
job_class: Job class
|
@@ -233,13 +231,14 @@ en:
|
|
233
231
|
jobs: Jobs
|
234
232
|
live_poll: Live Poll
|
235
233
|
name: "GoodJob 👍"
|
236
|
-
|
234
|
+
performance: Performance
|
237
235
|
processes: Processes
|
238
236
|
theme:
|
239
237
|
auto: Auto
|
240
238
|
dark: Dark
|
241
239
|
light: Light
|
242
240
|
theme: Theme
|
241
|
+
pending_migrations: GoodJob has pending database migrations.
|
243
242
|
secondary_navbar:
|
244
243
|
inspiration: Remember, you're doing a Good Job too!
|
245
244
|
last_updated: Last updated
|
@@ -250,5 +249,3 @@ en:
|
|
250
249
|
running: Running
|
251
250
|
scheduled: Scheduled
|
252
251
|
succeeded: Succeeded
|
253
|
-
shared:
|
254
|
-
needs_migration: Please run GoodJob migrations.
|
data/config/locales/es.yml
CHANGED
@@ -11,7 +11,6 @@ es:
|
|
11
11
|
batches:
|
12
12
|
index:
|
13
13
|
older_batches: Batches anteriores
|
14
|
-
pending_migrations: GoodJob tiene migraciones pendientes.
|
15
14
|
title: Batches
|
16
15
|
jobs:
|
17
16
|
actions:
|
@@ -48,7 +47,6 @@ es:
|
|
48
47
|
index:
|
49
48
|
no_cron_schedules_found: No hay tareas programadas.
|
50
49
|
title: Tareas Programadas
|
51
|
-
pending_migrations: Require las migraciones de GoodJob pendientes.
|
52
50
|
show:
|
53
51
|
cron_entry_key: Cron Entry Key
|
54
52
|
datetime:
|
@@ -196,8 +194,8 @@ es:
|
|
196
194
|
thousand: k
|
197
195
|
trillion: T
|
198
196
|
unit: ''
|
199
|
-
|
200
|
-
|
197
|
+
performance:
|
198
|
+
index:
|
201
199
|
average_duration: Duración promedio
|
202
200
|
executions: Ejecuciones
|
203
201
|
job_class: clase de trabajo
|
@@ -233,13 +231,14 @@ es:
|
|
233
231
|
jobs: Tareas
|
234
232
|
live_poll: En vivo
|
235
233
|
name: "GoodJob 👍"
|
236
|
-
|
234
|
+
performance: Actuación
|
237
235
|
processes: Procesos
|
238
236
|
theme:
|
239
237
|
auto: Auto
|
240
238
|
dark: Oscuro
|
241
239
|
light: Luz
|
242
240
|
theme: Tema
|
241
|
+
pending_migrations: GoodJob tiene migraciones pendientes.
|
243
242
|
secondary_navbar:
|
244
243
|
inspiration: "¡Recuerda, también tú estás haciendo un buen trabajo!"
|
245
244
|
last_updated: Última actualización
|
@@ -250,5 +249,3 @@ es:
|
|
250
249
|
running: Ejecutando
|
251
250
|
scheduled: Programado
|
252
251
|
succeeded: Exitoso
|
253
|
-
shared:
|
254
|
-
needs_migration: Ejecute las migraciones de GoodJob.
|
data/config/locales/fr.yml
CHANGED
@@ -11,7 +11,6 @@ fr:
|
|
11
11
|
batches:
|
12
12
|
index:
|
13
13
|
older_batches: Lots plus anciens
|
14
|
-
pending_migrations: GoodJob a des migrations de bases de données en attente.
|
15
14
|
title: Lots
|
16
15
|
jobs:
|
17
16
|
actions:
|
@@ -48,7 +47,6 @@ fr:
|
|
48
47
|
index:
|
49
48
|
no_cron_schedules_found: Aucune planification cron trouvée.
|
50
49
|
title: Entrées Cron
|
51
|
-
pending_migrations: Nécessite une migration de la base de données GoodJob en attente.
|
52
50
|
show:
|
53
51
|
cron_entry_key: Clé d'entrée Cron
|
54
52
|
datetime:
|
@@ -196,8 +194,8 @@ fr:
|
|
196
194
|
thousand: k
|
197
195
|
trillion: J
|
198
196
|
unit: ''
|
199
|
-
|
200
|
-
|
197
|
+
performance:
|
198
|
+
index:
|
201
199
|
average_duration: Durée moyenne
|
202
200
|
executions: Exécutions
|
203
201
|
job_class: Catégorie d'emplois
|
@@ -233,13 +231,14 @@ fr:
|
|
233
231
|
jobs: Jobs
|
234
232
|
live_poll: En direct
|
235
233
|
name: "GoodJob 👍"
|
236
|
-
|
234
|
+
performance: Performance
|
237
235
|
processes: Processus
|
238
236
|
theme:
|
239
237
|
auto: Auto
|
240
238
|
dark: Sombre
|
241
239
|
light: Lumière
|
242
240
|
theme: Thème
|
241
|
+
pending_migrations: GoodJob a des migrations de bases de données en attente.
|
243
242
|
secondary_navbar:
|
244
243
|
inspiration: N'oublie pas, toi aussi tu fais du bon boulot !
|
245
244
|
last_updated: Dernière mise à jour
|
@@ -250,5 +249,3 @@ fr:
|
|
250
249
|
running: En cours
|
251
250
|
scheduled: Planifiés
|
252
251
|
succeeded: Réussis
|
253
|
-
shared:
|
254
|
-
needs_migration: Veuillez exécuter des migrations GoodJob.
|
data/config/locales/it.yml
CHANGED
@@ -11,7 +11,6 @@ it:
|
|
11
11
|
batches:
|
12
12
|
index:
|
13
13
|
older_batches: Batch più vecchi
|
14
|
-
pending_migrations: GoodJob ha migrazioni del database in sospeso.
|
15
14
|
title: Batch
|
16
15
|
jobs:
|
17
16
|
actions:
|
@@ -48,7 +47,6 @@ it:
|
|
48
47
|
index:
|
49
48
|
no_cron_schedules_found: Nessuna pianificazione cron trovata.
|
50
49
|
title: Pianificazioni cron
|
51
|
-
pending_migrations: Richiede migrazione del database GoodJob in sospeso.
|
52
50
|
show:
|
53
51
|
cron_entry_key: Chiave voce cron
|
54
52
|
datetime:
|
@@ -196,8 +194,8 @@ it:
|
|
196
194
|
thousand: K
|
197
195
|
trillion: T
|
198
196
|
unit: ''
|
199
|
-
|
200
|
-
|
197
|
+
performance:
|
198
|
+
index:
|
201
199
|
average_duration: Durata media
|
202
200
|
executions: Esecuzioni
|
203
201
|
job_class: Classe di lavoro
|
@@ -233,13 +231,14 @@ it:
|
|
233
231
|
jobs: Job
|
234
232
|
live_poll: Live Poll
|
235
233
|
name: "GoodJob 👍"
|
236
|
-
|
234
|
+
performance: Prestazione
|
237
235
|
processes: Processi
|
238
236
|
theme:
|
239
237
|
auto: Auto
|
240
238
|
dark: Scuro
|
241
239
|
light: Chiaro
|
242
240
|
theme: Tema
|
241
|
+
pending_migrations: GoodJob ha migrazioni del database in sospeso.
|
243
242
|
secondary_navbar:
|
244
243
|
inspiration: Ricorda, stai facendo anche tu un Buon Lavoro!
|
245
244
|
last_updated: Ultimo aggiornamento
|
@@ -250,5 +249,3 @@ it:
|
|
250
249
|
running: In esecuzione
|
251
250
|
scheduled: Pianificato
|
252
251
|
succeeded: Riuscito
|
253
|
-
shared:
|
254
|
-
needs_migration: Esegui le migrazioni GoodJob.
|