good_job 3.18.3 → 3.19.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 +18 -0
- data/app/controllers/good_job/jobs_controller.rb +7 -0
- data/app/models/concerns/good_job/advisory_lockable.rb +49 -15
- data/app/models/good_job/base_record.rb +2 -2
- data/app/models/good_job/job.rb +36 -23
- data/app/views/good_job/jobs/_table.erb +7 -0
- data/app/views/good_job/shared/icons/_eject.html.erb +4 -0
- data/config/locales/de.yml +7 -0
- data/config/locales/en.yml +7 -0
- data/config/locales/es.yml +5 -0
- data/config/locales/fr.yml +7 -0
- data/config/locales/ja.yml +7 -0
- data/config/locales/nl.yml +7 -0
- data/config/locales/ru.yml +7 -0
- data/config/locales/tr.yml +7 -0
- data/config/locales/uk.yml +7 -0
- data/config/routes.rb +1 -0
- data/lib/good_job/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c66d226179c2cd55bfc539c943df468fc683f761b89cdc10606f03a6bb26f87
|
4
|
+
data.tar.gz: f72404539fb5bf7ef122cf65ed616276dd0457538b1319e253d6078e223ddbbb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98d03d3abdbcc20956e37e8c498c8fa57c1b2b091c5f50c0654aa75875d9d23ca02aeb78d67f5f2a8c961a9aabfc0ad3899fcf1867c2b4350dfe56584568a4eb
|
7
|
+
data.tar.gz: f0044b4c761371391c5aec83500efece2e000a6f9741a504f244208ae403b42fd39e1324fe1e753e3ae4d67c6ae92706f9a960ab5ec2745df547acd4e0927ac7
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v3.19.0](https://github.com/bensheldon/good_job/tree/v3.19.0) (2023-09-19)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.18.3...v3.19.0)
|
6
|
+
|
7
|
+
**Implemented enhancements:**
|
8
|
+
|
9
|
+
- "Force" discard jobs that are already running/runaway to prevent retry [\#1073](https://github.com/bensheldon/good_job/pull/1073) ([jgrau](https://github.com/jgrau))
|
10
|
+
|
11
|
+
**Closed issues:**
|
12
|
+
|
13
|
+
- Possible Memory Leak [\#1074](https://github.com/bensheldon/good_job/issues/1074)
|
14
|
+
- What's the best way to stop and discard a running job? [\#625](https://github.com/bensheldon/good_job/issues/625)
|
15
|
+
|
16
|
+
**Merged pull requests:**
|
17
|
+
|
18
|
+
- AdvisoryLockable: Abort record create if with\_advisory\_lock fails to acquire advisory lock [\#1078](https://github.com/bensheldon/good_job/pull/1078) ([bensheldon](https://github.com/bensheldon))
|
19
|
+
- Wrap all test background threads in Rails executors; better test logging/debugging [\#1077](https://github.com/bensheldon/good_job/pull/1077) ([bensheldon](https://github.com/bensheldon))
|
20
|
+
|
3
21
|
## [v3.18.3](https://github.com/bensheldon/good_job/tree/v3.18.3) (2023-09-16)
|
4
22
|
|
5
23
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.18.2...v3.18.3)
|
@@ -3,6 +3,7 @@
|
|
3
3
|
module GoodJob
|
4
4
|
class JobsController < GoodJob::ApplicationController
|
5
5
|
DISCARD_MESSAGE = "Discarded through dashboard"
|
6
|
+
FORCE_DISCARD_MESSAGE = "Force discarded through dashboard"
|
6
7
|
|
7
8
|
ACTIONS = {
|
8
9
|
discard: "discarded",
|
@@ -66,6 +67,12 @@ module GoodJob
|
|
66
67
|
redirect_back(fallback_location: jobs_path, notice: t(".notice"))
|
67
68
|
end
|
68
69
|
|
70
|
+
def force_discard
|
71
|
+
@job = Job.find(params[:id])
|
72
|
+
@job.force_discard_job(FORCE_DISCARD_MESSAGE)
|
73
|
+
redirect_back(fallback_location: jobs_path, notice: t(".notice"))
|
74
|
+
end
|
75
|
+
|
69
76
|
def reschedule
|
70
77
|
@job = Job.find(params[:id])
|
71
78
|
@job.reschedule_job
|
@@ -133,7 +133,12 @@ module GoodJob
|
|
133
133
|
# @return [Boolean]
|
134
134
|
attr_accessor :create_with_advisory_lock
|
135
135
|
|
136
|
-
after_create
|
136
|
+
after_create lambda {
|
137
|
+
advisory_lock || begin
|
138
|
+
errors.add(self.class.advisory_lockable_column, "Failed to acquire advisory lock: #{lockable_key}")
|
139
|
+
raise ActiveRecord::RecordInvalid # do not reference the record because it can cause I18n missing translation error
|
140
|
+
end
|
141
|
+
}, if: :create_with_advisory_lock
|
137
142
|
end
|
138
143
|
|
139
144
|
class_methods do
|
@@ -222,6 +227,47 @@ module GoodJob
|
|
222
227
|
connection.exec_query(pg_or_jdbc_query(query), 'GoodJob::Lockable Advisory Unlock', binds).first['unlocked']
|
223
228
|
end
|
224
229
|
|
230
|
+
# Tests whether the provided key has an advisory lock on it.
|
231
|
+
# @param key [String, Symbol] Key to test lock against
|
232
|
+
# @return [Boolean]
|
233
|
+
def advisory_locked_key?(key)
|
234
|
+
query = <<~SQL.squish
|
235
|
+
SELECT 1 AS one
|
236
|
+
FROM pg_locks
|
237
|
+
WHERE pg_locks.locktype = 'advisory'
|
238
|
+
AND pg_locks.objsubid = 1
|
239
|
+
AND pg_locks.classid = ('x' || substr(md5($1::text), 1, 16))::bit(32)::int
|
240
|
+
AND pg_locks.objid = (('x' || substr(md5($2::text), 1, 16))::bit(64) << 32)::bit(32)::int
|
241
|
+
LIMIT 1
|
242
|
+
SQL
|
243
|
+
binds = [
|
244
|
+
ActiveRecord::Relation::QueryAttribute.new('key', key, ActiveRecord::Type::String.new),
|
245
|
+
ActiveRecord::Relation::QueryAttribute.new('key', key, ActiveRecord::Type::String.new),
|
246
|
+
]
|
247
|
+
connection.exec_query(pg_or_jdbc_query(query), 'GoodJob::Lockable Advisory Locked?', binds).any?
|
248
|
+
end
|
249
|
+
|
250
|
+
# Tests whether this record is locked by the current database session.
|
251
|
+
# @param key [String, Symbol] Key to test lock against
|
252
|
+
# @return [Boolean]
|
253
|
+
def owns_advisory_lock_key?(key)
|
254
|
+
query = <<~SQL.squish
|
255
|
+
SELECT 1 AS one
|
256
|
+
FROM pg_locks
|
257
|
+
WHERE pg_locks.locktype = 'advisory'
|
258
|
+
AND pg_locks.objsubid = 1
|
259
|
+
AND pg_locks.classid = ('x' || substr(md5($1::text), 1, 16))::bit(32)::int
|
260
|
+
AND pg_locks.objid = (('x' || substr(md5($2::text), 1, 16))::bit(64) << 32)::bit(32)::int
|
261
|
+
AND pg_locks.pid = pg_backend_pid()
|
262
|
+
LIMIT 1
|
263
|
+
SQL
|
264
|
+
binds = [
|
265
|
+
ActiveRecord::Relation::QueryAttribute.new('key', key, ActiveRecord::Type::String.new),
|
266
|
+
ActiveRecord::Relation::QueryAttribute.new('key', key, ActiveRecord::Type::String.new),
|
267
|
+
]
|
268
|
+
connection.exec_query(pg_or_jdbc_query(query), 'GoodJob::Lockable Owns Advisory Lock?', binds).any?
|
269
|
+
end
|
270
|
+
|
225
271
|
def _advisory_lockable_column
|
226
272
|
advisory_lockable_column || primary_key
|
227
273
|
end
|
@@ -318,20 +364,7 @@ module GoodJob
|
|
318
364
|
# @param key [String, Symbol] Key to test lock against
|
319
365
|
# @return [Boolean]
|
320
366
|
def advisory_locked?(key: lockable_key)
|
321
|
-
|
322
|
-
SELECT 1 AS one
|
323
|
-
FROM pg_locks
|
324
|
-
WHERE pg_locks.locktype = 'advisory'
|
325
|
-
AND pg_locks.objsubid = 1
|
326
|
-
AND pg_locks.classid = ('x' || substr(md5($1::text), 1, 16))::bit(32)::int
|
327
|
-
AND pg_locks.objid = (('x' || substr(md5($2::text), 1, 16))::bit(64) << 32)::bit(32)::int
|
328
|
-
LIMIT 1
|
329
|
-
SQL
|
330
|
-
binds = [
|
331
|
-
ActiveRecord::Relation::QueryAttribute.new('key', key, ActiveRecord::Type::String.new),
|
332
|
-
ActiveRecord::Relation::QueryAttribute.new('key', key, ActiveRecord::Type::String.new),
|
333
|
-
]
|
334
|
-
self.class.connection.exec_query(pg_or_jdbc_query(query), 'GoodJob::Lockable Advisory Locked?', binds).any?
|
367
|
+
self.class.advisory_locked_key?(key)
|
335
368
|
end
|
336
369
|
|
337
370
|
# Tests whether this record does not have an advisory lock on it.
|
@@ -345,6 +378,7 @@ module GoodJob
|
|
345
378
|
# @param key [String, Symbol] Key to test lock against
|
346
379
|
# @return [Boolean]
|
347
380
|
def owns_advisory_lock?(key: lockable_key)
|
381
|
+
self.class.owns_advisory_lock_key?(key)
|
348
382
|
query = <<~SQL.squish
|
349
383
|
SELECT 1 AS one
|
350
384
|
FROM pg_locks
|
@@ -30,10 +30,10 @@ module GoodJob
|
|
30
30
|
|
31
31
|
# Runs the block with self.logger silenced.
|
32
32
|
# If self.logger is nil, simply runs the block.
|
33
|
-
def self.with_logger_silenced(&block)
|
33
|
+
def self.with_logger_silenced(silent: true, &block)
|
34
34
|
# Assign to a local variable, just in case it's modified in another thread concurrently
|
35
35
|
logger = self.logger
|
36
|
-
if logger.respond_to?
|
36
|
+
if silent && logger.respond_to?(:silence)
|
37
37
|
logger.silence(&block)
|
38
38
|
else
|
39
39
|
yield
|
data/app/models/good_job/job.rb
CHANGED
@@ -215,32 +215,17 @@ module GoodJob
|
|
215
215
|
# @return [void]
|
216
216
|
def discard_job(message)
|
217
217
|
with_advisory_lock do
|
218
|
-
|
219
|
-
active_job = execution.active_job(ignore_deserialization_errors: true)
|
220
|
-
|
221
|
-
raise ActionForStateMismatchError if execution.finished_at.present?
|
222
|
-
|
223
|
-
job_error = GoodJob::Job::DiscardJobError.new(message)
|
224
|
-
|
225
|
-
update_execution = proc do
|
226
|
-
execution.update(
|
227
|
-
{
|
228
|
-
finished_at: Time.current,
|
229
|
-
error: GoodJob::Execution.format_error(job_error),
|
230
|
-
}.tap do |attrs|
|
231
|
-
attrs[:error_event] = ERROR_EVENT_DISCARDED if self.class.error_event_migrated?
|
232
|
-
end
|
233
|
-
)
|
234
|
-
end
|
235
|
-
|
236
|
-
if active_job.respond_to?(:instrument)
|
237
|
-
active_job.send :instrument, :discard, error: job_error, &update_execution
|
238
|
-
else
|
239
|
-
update_execution.call
|
240
|
-
end
|
218
|
+
_discard_job(message)
|
241
219
|
end
|
242
220
|
end
|
243
221
|
|
222
|
+
# Force discard a job so that it will not be executed further. Force discard allows discarding
|
223
|
+
# a running job.
|
224
|
+
# This action will add a {DiscardJobError} to the job's {Execution} and mark it as finished.
|
225
|
+
def force_discard_job(message)
|
226
|
+
_discard_job(message)
|
227
|
+
end
|
228
|
+
|
244
229
|
# Reschedule a scheduled job so that it executes immediately (or later) by the next available execution thread.
|
245
230
|
# @param scheduled_at [DateTime, Time] When to reschedule the job
|
246
231
|
# @return [void]
|
@@ -277,5 +262,33 @@ module GoodJob
|
|
277
262
|
def _head?
|
278
263
|
_execution_id == head_execution(reload: true).id
|
279
264
|
end
|
265
|
+
|
266
|
+
private
|
267
|
+
|
268
|
+
def _discard_job(message)
|
269
|
+
execution = head_execution(reload: true)
|
270
|
+
active_job = execution.active_job(ignore_deserialization_errors: true)
|
271
|
+
|
272
|
+
raise ActionForStateMismatchError if execution.finished_at.present?
|
273
|
+
|
274
|
+
job_error = GoodJob::Job::DiscardJobError.new(message)
|
275
|
+
|
276
|
+
update_execution = proc do
|
277
|
+
execution.update(
|
278
|
+
{
|
279
|
+
finished_at: Time.current,
|
280
|
+
error: GoodJob::Execution.format_error(job_error),
|
281
|
+
}.tap do |attrs|
|
282
|
+
attrs[:error_event] = ERROR_EVENT_DISCARDED if self.class.error_event_migrated?
|
283
|
+
end
|
284
|
+
)
|
285
|
+
end
|
286
|
+
|
287
|
+
if active_job.respond_to?(:instrument)
|
288
|
+
active_job.send :instrument, :discard, error: job_error, &update_execution
|
289
|
+
else
|
290
|
+
update_execution.call
|
291
|
+
end
|
292
|
+
end
|
280
293
|
end
|
281
294
|
end
|
@@ -127,6 +127,13 @@
|
|
127
127
|
<%=t "good_job.actions.discard" %>
|
128
128
|
<% end %>
|
129
129
|
</li>
|
130
|
+
<li>
|
131
|
+
<% job_force_discardable = job.status.in? [:running] %>
|
132
|
+
<%= link_to force_discard_job_path(job.id), method: :put, class: "dropdown-item #{'disabled' unless job_force_discardable}", title: t("good_job.jobs.actions.force_discard"), data: { confirm: t("good_job.jobs.actions.confirm_force_discard"), disable: true } do %>
|
133
|
+
<%= render "good_job/shared/icons/eject" %>
|
134
|
+
<%=t "good_job.actions.force_discard" %>
|
135
|
+
<% end %>
|
136
|
+
</li>
|
130
137
|
<li>
|
131
138
|
<%= link_to retry_job_path(job.id), method: :put, class: "dropdown-item #{'disabled' unless job.status == :discarded}", title: t("good_job.jobs.actions.retry"), data: { confirm: t("good_job.jobs.actions.confirm_retry"), disable: true } do %>
|
132
139
|
<%= render "good_job/shared/icons/arrow_clockwise" %>
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<!-- https://icons.getbootstrap.com/icons/eject/ -->
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eject" viewBox="0 0 16 16">
|
3
|
+
<path d="M7.27 1.047a1 1 0 0 1 1.46 0l6.345 6.77c.6.638.146 1.683-.73 1.683H1.656C.78 9.5.326 8.455.926 7.816L7.27 1.047zM14.346 8.5 8 1.731 1.654 8.5h12.692zM.5 11.5a1 1 0 0 1 1-1h13a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1h-13a1 1 0 0 1-1-1v-1zm14 0h-13v1h13v-1z" />
|
4
|
+
</svg>
|
data/config/locales/de.yml
CHANGED
@@ -4,6 +4,7 @@ de:
|
|
4
4
|
actions:
|
5
5
|
destroy: Zerstören
|
6
6
|
discard: Verwerfen
|
7
|
+
force_discard: Verwerfen erzwingen
|
7
8
|
inspect: Prüfen
|
8
9
|
reschedule: Umplanen
|
9
10
|
retry: Wiederholen
|
@@ -110,10 +111,14 @@ de:
|
|
110
111
|
actions:
|
111
112
|
confirm_destroy: Sind Sie sicher, dass Sie den Job zerstören wollen?
|
112
113
|
confirm_discard: Sind Sie sicher, dass Sie den Job verwerfen wollen?
|
114
|
+
confirm_force_discard: 'Sind Sie sicher, dass Sie das Verwerfen dieses Jobs erzwingen möchten? Der Job wird als verworfen markiert, aber der laufende Job wird nicht gestoppt – er wird jedoch bei Fehlern nicht erneut versucht.
|
115
|
+
|
116
|
+
'
|
113
117
|
confirm_reschedule: Möchten Sie den Auftrag wirklich verschieben?
|
114
118
|
confirm_retry: Möchten Sie den Job wirklich wiederholen?
|
115
119
|
destroy: Arbeit vernichten
|
116
120
|
discard: Auftrag verwerfen
|
121
|
+
force_discard: Job verwerfen erzwingen
|
117
122
|
reschedule: Auftrag neu planen
|
118
123
|
retry: Job wiederholen
|
119
124
|
destroy:
|
@@ -124,6 +129,8 @@ de:
|
|
124
129
|
in_queue: in der Warteschlange
|
125
130
|
runtime: Laufzeit
|
126
131
|
title: Hinrichtungen
|
132
|
+
force_discard:
|
133
|
+
notice: Der Job wurde zwangsweise verworfen. Die Ausführung wird fortgesetzt, bei Fehlern wird der Vorgang jedoch nicht wiederholt
|
127
134
|
index:
|
128
135
|
job_pagination: Job-Paginierung
|
129
136
|
older_jobs: Ältere Berufe
|
data/config/locales/en.yml
CHANGED
@@ -4,6 +4,7 @@ en:
|
|
4
4
|
actions:
|
5
5
|
destroy: Destroy
|
6
6
|
discard: Discard
|
7
|
+
force_discard: Force discard
|
7
8
|
inspect: Inspect
|
8
9
|
reschedule: Reschedule
|
9
10
|
retry: Retry
|
@@ -110,10 +111,14 @@ en:
|
|
110
111
|
actions:
|
111
112
|
confirm_destroy: Are you sure you want to destroy the job?
|
112
113
|
confirm_discard: Are you usure you want to discard the job?
|
114
|
+
confirm_force_discard: 'Are you sure you want to force discard this job? The job will be marked as discarded but the running job will not be stopped - it will, however, not be retried on failures.
|
115
|
+
|
116
|
+
'
|
113
117
|
confirm_reschedule: Are you sure you want to reschedule the job?
|
114
118
|
confirm_retry: Are you sure you want to retry the job?
|
115
119
|
destroy: Destroy job
|
116
120
|
discard: Discard job
|
121
|
+
force_discard: Force discard job
|
117
122
|
reschedule: Reschedule job
|
118
123
|
retry: Retry job
|
119
124
|
destroy:
|
@@ -124,6 +129,8 @@ en:
|
|
124
129
|
in_queue: in queue
|
125
130
|
runtime: runtime
|
126
131
|
title: Executions
|
132
|
+
force_discard:
|
133
|
+
notice: Job has been force discarded. It will continue to run but it will not be retried on failures
|
127
134
|
index:
|
128
135
|
job_pagination: Job pagination
|
129
136
|
older_jobs: Older jobs
|
data/config/locales/es.yml
CHANGED
@@ -4,6 +4,7 @@ es:
|
|
4
4
|
actions:
|
5
5
|
destroy: Eliminar
|
6
6
|
discard: Descartar
|
7
|
+
force_discard: Forzar descarte
|
7
8
|
inspect: Inspeccionar
|
8
9
|
reschedule: Reprogramar
|
9
10
|
retry: Reintentar
|
@@ -110,10 +111,12 @@ es:
|
|
110
111
|
actions:
|
111
112
|
confirm_destroy: "¿Estás seguro que querés eliminar esta tarea?"
|
112
113
|
confirm_discard: "¿Estás seguro que querés descartar esta tarea?"
|
114
|
+
confirm_force_discard: "¿Está seguro de que desea forzar el descarte de este trabajo? El trabajo se marcará como descartado, pero el trabajo en ejecución no se detendrá; sin embargo, no se volverá a intentar en caso de falla.\n"
|
113
115
|
confirm_reschedule: "¿Estás seguro que querés reprogramar esta tarea?"
|
114
116
|
confirm_retry: "¿Estás seguro que querés reintentar esta tarea?"
|
115
117
|
destroy: Eliminar tarea
|
116
118
|
discard: Descartar tarea
|
119
|
+
force_discard: Forzar el descarte del trabajo
|
117
120
|
reschedule: Reprogramar tarea
|
118
121
|
retry: Reiuntentar tarea
|
119
122
|
destroy:
|
@@ -124,6 +127,8 @@ es:
|
|
124
127
|
in_queue: en cola
|
125
128
|
runtime: en ejecución
|
126
129
|
title: Ejecuciones
|
130
|
+
force_discard:
|
131
|
+
notice: Job ha sido descartado a la fuerza. Continuará ejecutándose pero no se volverá a intentar en caso de fallas.
|
127
132
|
index:
|
128
133
|
job_pagination: Paginación de tareas
|
129
134
|
older_jobs: Tareas anteriores
|
data/config/locales/fr.yml
CHANGED
@@ -4,6 +4,7 @@ fr:
|
|
4
4
|
actions:
|
5
5
|
destroy: Détruire
|
6
6
|
discard: Mettre au rebut
|
7
|
+
force_discard: Forcer le rejet
|
7
8
|
inspect: Inspecter
|
8
9
|
reschedule: Reprogrammer
|
9
10
|
retry: Recommencez
|
@@ -110,10 +111,14 @@ fr:
|
|
110
111
|
actions:
|
111
112
|
confirm_destroy: Voulez-vous vraiment détruire le job ?
|
112
113
|
confirm_discard: Voulez-vous vraiment mettre au rebut le job ?
|
114
|
+
confirm_force_discard: 'Êtes-vous sûr de vouloir forcer l''abandon de cette tâche ? Le travail sera marqué comme abandonné mais le travail en cours d''exécution ne sera pas arrêté - il ne sera cependant pas réessayé en cas d''échec.
|
115
|
+
|
116
|
+
'
|
113
117
|
confirm_reschedule: Voulez-vous vraiment replanifier le job ?
|
114
118
|
confirm_retry: Voulez-vous vraiment réessayer le job ?
|
115
119
|
destroy: Détruire le job
|
116
120
|
discard: Mettre au rebut le job
|
121
|
+
force_discard: Forcer l'abandon du travail
|
117
122
|
reschedule: Replanifier le job
|
118
123
|
retry: Réessayer le job
|
119
124
|
destroy:
|
@@ -124,6 +129,8 @@ fr:
|
|
124
129
|
in_queue: Dans la file d'attente
|
125
130
|
runtime: Durée
|
126
131
|
title: Exécutions
|
132
|
+
force_discard:
|
133
|
+
notice: Le travail a été abandonné de force. Il continuera à fonctionner mais il ne sera pas réessayé en cas d'échec
|
127
134
|
index:
|
128
135
|
job_pagination: Pagination du job
|
129
136
|
older_jobs: Jobs plus anciens
|
data/config/locales/ja.yml
CHANGED
@@ -4,6 +4,7 @@ ja:
|
|
4
4
|
actions:
|
5
5
|
destroy: 削除する
|
6
6
|
discard: 破棄する
|
7
|
+
force_discard: 強制破棄
|
7
8
|
inspect: 調査する
|
8
9
|
reschedule: 再スケジュールする
|
9
10
|
retry: 再試行する
|
@@ -110,10 +111,14 @@ ja:
|
|
110
111
|
actions:
|
111
112
|
confirm_destroy: ジョブを削除してもよろしいですか?
|
112
113
|
confirm_discard: ジョブを破棄してもよろしいですか?
|
114
|
+
confirm_force_discard: 'このジョブを強制的に破棄してもよろしいですか?ジョブは破棄済みとしてマークされますが、実行中のジョブは停止されません。ただし、失敗した場合は再試行されません。
|
115
|
+
|
116
|
+
'
|
113
117
|
confirm_reschedule: ジョブを再スケジュールしてもよろしいですか?
|
114
118
|
confirm_retry: ジョブを再試行してもよろしいですか?
|
115
119
|
destroy: ジョブを削除
|
116
120
|
discard: ジョブを破棄
|
121
|
+
force_discard: ジョブを強制的に破棄する
|
117
122
|
reschedule: ジョブを再スケジュール
|
118
123
|
retry: ジョブを再試行
|
119
124
|
destroy:
|
@@ -124,6 +129,8 @@ ja:
|
|
124
129
|
in_queue: 待機中
|
125
130
|
runtime: 実行時間
|
126
131
|
title: 実行
|
132
|
+
force_discard:
|
133
|
+
notice: ジョブは強制的に破棄されました。実行は継続されますが、失敗した場合は再試行されません
|
127
134
|
index:
|
128
135
|
job_pagination: ジョブのページネーション
|
129
136
|
older_jobs: 古いジョブ
|
data/config/locales/nl.yml
CHANGED
@@ -4,6 +4,7 @@ nl:
|
|
4
4
|
actions:
|
5
5
|
destroy: Vernietigen
|
6
6
|
discard: Weggooien
|
7
|
+
force_discard: Forceer weggooien
|
7
8
|
inspect: Inspecteren
|
8
9
|
reschedule: Opnieuw plannen
|
9
10
|
retry: Opnieuw proberen
|
@@ -110,10 +111,14 @@ nl:
|
|
110
111
|
actions:
|
111
112
|
confirm_destroy: Weet je zeker dat je de baan wilt vernietigen?
|
112
113
|
confirm_discard: Wilt u de baan afwijzen?
|
114
|
+
confirm_force_discard: 'Weet u zeker dat u deze taak geforceerd wilt weggooien? De taak wordt gemarkeerd als verwijderd, maar de lopende taak wordt niet gestopt. Bij fouten wordt deze echter niet opnieuw geprobeerd.
|
115
|
+
|
116
|
+
'
|
113
117
|
confirm_reschedule: Weet u zeker dat u de taak opnieuw wilt inplannen?
|
114
118
|
confirm_retry: Weet u zeker dat u de taak opnieuw wilt proberen?
|
115
119
|
destroy: Baan vernietigen
|
116
120
|
discard: Gooi de baan weg
|
121
|
+
force_discard: Forceer taak weggooien
|
117
122
|
reschedule: Taak opnieuw plannen
|
118
123
|
retry: Taak opnieuw proberen
|
119
124
|
destroy:
|
@@ -124,6 +129,8 @@ nl:
|
|
124
129
|
in_queue: in de wachtrij
|
125
130
|
runtime: looptijd
|
126
131
|
title: Executies
|
132
|
+
force_discard:
|
133
|
+
notice: Baan is gedwongen verwijderd. Het blijft actief, maar wordt niet opnieuw geprobeerd als er fouten optreden
|
127
134
|
index:
|
128
135
|
job_pagination: Taak paginering
|
129
136
|
older_jobs: Oudere banen
|
data/config/locales/ru.yml
CHANGED
@@ -4,6 +4,7 @@ ru:
|
|
4
4
|
actions:
|
5
5
|
destroy: Разрушать
|
6
6
|
discard: Отказаться
|
7
|
+
force_discard: Принудительно отменить
|
7
8
|
inspect: Осмотреть
|
8
9
|
reschedule: Перенести
|
9
10
|
retry: Повторить попытку
|
@@ -134,10 +135,14 @@ ru:
|
|
134
135
|
actions:
|
135
136
|
confirm_destroy: Вы уверены, что хотите уничтожить задание?
|
136
137
|
confirm_discard: Вы уверены, что хотите отказаться от задания?
|
138
|
+
confirm_force_discard: 'Вы уверены, что хотите принудительно отменить это задание? Задание будет помечено как отброшенное, но выполняемое задание не будет остановлено, однако в случае сбоя оно не будет повторено.
|
139
|
+
|
140
|
+
'
|
137
141
|
confirm_reschedule: Вы уверены, что хотите перенести задание?
|
138
142
|
confirm_retry: Вы уверены, что хотите повторить задание?
|
139
143
|
destroy: Уничтожить работу
|
140
144
|
discard: Отменить задание
|
145
|
+
force_discard: Принудительно отменить задание
|
141
146
|
reschedule: Перенести задание
|
142
147
|
retry: Повторить задание
|
143
148
|
destroy:
|
@@ -148,6 +153,8 @@ ru:
|
|
148
153
|
in_queue: в очереди
|
149
154
|
runtime: время выполнения
|
150
155
|
title: Казни
|
156
|
+
force_discard:
|
157
|
+
notice: Иов был принудительно отброшен. Он продолжит работу, но не будет повторяться в случае сбоя.
|
151
158
|
index:
|
152
159
|
job_pagination: Пагинация вакансий
|
153
160
|
older_jobs: Старые рабочие места
|
data/config/locales/tr.yml
CHANGED
@@ -4,6 +4,7 @@ tr:
|
|
4
4
|
actions:
|
5
5
|
destroy: Sil
|
6
6
|
discard: İptal Et
|
7
|
+
force_discard: Atmaya zorla
|
7
8
|
inspect: İncele
|
8
9
|
reschedule: Yeniden planla
|
9
10
|
retry: Tekrar dene
|
@@ -110,10 +111,14 @@ tr:
|
|
110
111
|
actions:
|
111
112
|
confirm_destroy: Bu işi silmek istediğinizden emin misiniz?
|
112
113
|
confirm_discard: Bu işi iptal etmek istediğinizden emin misiniz?
|
114
|
+
confirm_force_discard: 'Bu işi zorla iptal etmek istediğinizden emin misiniz? İş atıldı olarak işaretlenecek ancak devam eden iş durdurulmayacak; ancak başarısızlık durumunda yeniden denenmeyecek.
|
115
|
+
|
116
|
+
'
|
113
117
|
confirm_reschedule: Bu işi yeniden planlamak istediğinizden emin misiniz?
|
114
118
|
confirm_retry: Bu işi tekrar denemek istediğinizden emin misiniz?
|
115
119
|
destroy: İşi Sil
|
116
120
|
discard: İşi İptal Et
|
121
|
+
force_discard: İşi zorla atmaya zorla
|
117
122
|
reschedule: İşi Yeniden Planla
|
118
123
|
retry: İşi Tekrar Dene
|
119
124
|
destroy:
|
@@ -124,6 +129,8 @@ tr:
|
|
124
129
|
in_queue: sırada
|
125
130
|
runtime: çalışma süresi
|
126
131
|
title: İşlemler
|
132
|
+
force_discard:
|
133
|
+
notice: İş zorla atıldı. Çalışmaya devam edecek ancak arıza durumunda yeniden denenmeyecek
|
127
134
|
index:
|
128
135
|
job_pagination: İş sayfalandırması
|
129
136
|
older_jobs: Daha eski işler
|
data/config/locales/uk.yml
CHANGED
@@ -4,6 +4,7 @@ uk:
|
|
4
4
|
actions:
|
5
5
|
destroy: Видалити
|
6
6
|
discard: Відхилити
|
7
|
+
force_discard: Примусово скинути
|
7
8
|
inspect: Оглянути
|
8
9
|
reschedule: Перепланувати
|
9
10
|
retry: Повторити
|
@@ -134,10 +135,14 @@ uk:
|
|
134
135
|
actions:
|
135
136
|
confirm_destroy: Ви впевнені, що хочете видалити завдання?
|
136
137
|
confirm_discard: Ви впевнені, що хочете відхилити завдання?
|
138
|
+
confirm_force_discard: 'Ви впевнені, що хочете примусово скасувати цю роботу? Завдання буде позначено як відхилене, але виконуване завдання не буде зупинено – однак його не буде повторено у випадку помилок.
|
139
|
+
|
140
|
+
'
|
137
141
|
confirm_reschedule: Ви впевнені, що хочете перепланувати завдання?
|
138
142
|
confirm_retry: Ви впевнені, що хочете повторити завдання?
|
139
143
|
destroy: Видалити завдання
|
140
144
|
discard: Відхилити завдання
|
145
|
+
force_discard: Примусово скасувати завдання
|
141
146
|
reschedule: Перепланувати завдання
|
142
147
|
retry: Повторити завдання
|
143
148
|
destroy:
|
@@ -148,6 +153,8 @@ uk:
|
|
148
153
|
in_queue: у черзі
|
149
154
|
runtime: час виконання
|
150
155
|
title: Виконання
|
156
|
+
force_discard:
|
157
|
+
notice: Роботу примусово скасовано. Він продовжуватиме працювати, але не буде повторюватися в разі помилок
|
151
158
|
index:
|
152
159
|
job_pagination: Пагінація робіт
|
153
160
|
older_jobs: Старі роботи
|
data/config/routes.rb
CHANGED
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: 3.
|
4
|
+
version: 3.19.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: 2023-09-
|
11
|
+
date: 2023-09-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activejob
|
@@ -313,6 +313,7 @@ files:
|
|
313
313
|
- app/views/good_job/shared/icons/_clock.html.erb
|
314
314
|
- app/views/good_job/shared/icons/_dash_circle.html.erb
|
315
315
|
- app/views/good_job/shared/icons/_dots.html.erb
|
316
|
+
- app/views/good_job/shared/icons/_eject.html.erb
|
316
317
|
- app/views/good_job/shared/icons/_exclamation.html.erb
|
317
318
|
- app/views/good_job/shared/icons/_info.html.erb
|
318
319
|
- app/views/good_job/shared/icons/_moon_stars_fill.html.erb
|