good_job 3.14.2 → 3.15.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +50 -0
- data/README.md +2 -1
- data/app/controllers/good_job/application_controller.rb +4 -1
- data/app/controllers/good_job/cron_entries_controller.rb +4 -4
- data/app/controllers/good_job/jobs_controller.rb +4 -4
- data/app/filters/good_job/base_filter.rb +1 -1
- data/app/helpers/good_job/application_helper.rb +11 -2
- data/app/models/good_job/base_execution.rb +44 -0
- data/app/models/good_job/execution.rb +3 -11
- data/app/models/good_job/job.rb +1 -34
- data/app/views/good_job/batches/_jobs.erb +18 -18
- data/app/views/good_job/batches/_table.erb +15 -15
- data/app/views/good_job/batches/index.html.erb +3 -3
- data/app/views/good_job/batches/show.html.erb +4 -4
- data/app/views/good_job/cron_entries/index.html.erb +15 -15
- data/app/views/good_job/cron_entries/show.html.erb +1 -1
- data/app/views/good_job/jobs/_executions.erb +7 -7
- data/app/views/good_job/jobs/_table.erb +29 -29
- data/app/views/good_job/jobs/index.html.erb +3 -3
- data/app/views/good_job/jobs/show.html.erb +14 -14
- data/app/views/good_job/processes/index.html.erb +8 -8
- data/app/views/good_job/shared/_filter.erb +12 -12
- data/app/views/good_job/shared/_navbar.erb +5 -4
- data/config/locales/de.yml +219 -0
- data/config/locales/en.yml +137 -0
- data/config/locales/es.yml +152 -5
- data/config/locales/fr.yml +138 -1
- data/config/locales/nl.yml +138 -1
- data/config/locales/ru.yml +140 -1
- data/config/locales/ua.yml +172 -57
- data/lib/good_job/adapter.rb +1 -0
- data/lib/good_job/cli.rb +1 -1
- data/lib/good_job/version.rb +1 -1
- metadata +5 -4
- data/app/models/good_job/active_job_job.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95ede69036445ced25b5afed25912ce509a171d7311e7a5c2c91d3b9615c0482
|
4
|
+
data.tar.gz: 141500358218a98d7e84b5415b1f1d8afb92243a5695928370b5497906716ae3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 997b09e9a348d9b11fd67521a54222909f4e495ecede63bcc253473e4a8544fdaa40f3e77171dbbb35692f8f1f77290b51cbf80bfc50817422f94efdbed3c83a
|
7
|
+
data.tar.gz: f64e80caca4d1c31449af26e146b77a0d71c53ca09bc2c8370c0190daafe0565380d0bc60ca42fb20a84e5be41c50c23b7f4b4c0674f69a3bff47c5c43fcf537
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,55 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v3.15.1](https://github.com/bensheldon/good_job/tree/v3.15.1) (2023-04-17)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.15.0...v3.15.1)
|
6
|
+
|
7
|
+
**Implemented enhancements:**
|
8
|
+
|
9
|
+
- Support for Batches? [\#417](https://github.com/bensheldon/good_job/issues/417)
|
10
|
+
|
11
|
+
**Fixed bugs:**
|
12
|
+
|
13
|
+
- Fix setting of locale via routes `mount ... defaults: { locale: :en }` [\#923](https://github.com/bensheldon/good_job/pull/923) ([bensheldon](https://github.com/bensheldon))
|
14
|
+
- Set `successfully_enqueued?` when using `perform_all_later` [\#917](https://github.com/bensheldon/good_job/pull/917) ([bensheldon](https://github.com/bensheldon))
|
15
|
+
|
16
|
+
**Closed issues:**
|
17
|
+
|
18
|
+
- GoodJob has pending database migrations after v2 -\> v3 [\#920](https://github.com/bensheldon/good_job/issues/920)
|
19
|
+
- Batch docs in README suggest `Batch#add` is a class method, but it's not [\#912](https://github.com/bensheldon/good_job/issues/912)
|
20
|
+
- How do I clear queue during tests? [\#887](https://github.com/bensheldon/good_job/issues/887)
|
21
|
+
- Implement batch functionality [\#691](https://github.com/bensheldon/good_job/issues/691)
|
22
|
+
|
23
|
+
**Merged pull requests:**
|
24
|
+
|
25
|
+
- In tests, directly use `connection.truncate_tables` instead of `ActiveRecord::Tasks::DatabaseTasks.truncate_all` [\#918](https://github.com/bensheldon/good_job/pull/918) ([bensheldon](https://github.com/bensheldon))
|
26
|
+
- Use `GoodJob.capsule` in CLI instead of creating a new Capsule [\#916](https://github.com/bensheldon/good_job/pull/916) ([bensheldon](https://github.com/bensheldon))
|
27
|
+
- Fix lint: missing fr and nl translations; readme whitespace [\#914](https://github.com/bensheldon/good_job/pull/914) ([bensheldon](https://github.com/bensheldon))
|
28
|
+
- Switches from Chrome to Chromium to support Apple M1/Arm CPUs [\#910](https://github.com/bensheldon/good_job/pull/910) ([ckdake](https://github.com/ckdake))
|
29
|
+
- Bump erb\_lint from 0.3.1 to 0.4.0 [\#906](https://github.com/bensheldon/good_job/pull/906) ([dependabot[bot]](https://github.com/apps/dependabot))
|
30
|
+
|
31
|
+
## [v3.15.0](https://github.com/bensheldon/good_job/tree/v3.15.0) (2023-04-02)
|
32
|
+
|
33
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.14.2...v3.15.0)
|
34
|
+
|
35
|
+
**Implemented enhancements:**
|
36
|
+
|
37
|
+
- Extract more Dashboard strings into localization strings [\#899](https://github.com/bensheldon/good_job/pull/899) ([patriciomacadden](https://github.com/patriciomacadden))
|
38
|
+
|
39
|
+
**Closed issues:**
|
40
|
+
|
41
|
+
- ActionView::Template::Error - undefined method `symbolize\_keys' [\#889](https://github.com/bensheldon/good_job/issues/889)
|
42
|
+
|
43
|
+
**Merged pull requests:**
|
44
|
+
|
45
|
+
- Bump benchmark-ips from 2.11.0 to 2.12.0 [\#907](https://github.com/bensheldon/good_job/pull/907) ([dependabot[bot]](https://github.com/apps/dependabot))
|
46
|
+
- Bump selenium-webdriver from 4.8.1 to 4.8.6 [\#905](https://github.com/bensheldon/good_job/pull/905) ([dependabot[bot]](https://github.com/apps/dependabot))
|
47
|
+
- Bump rails from 7.0.4.2 to 7.0.4.3 [\#904](https://github.com/bensheldon/good_job/pull/904) ([dependabot[bot]](https://github.com/apps/dependabot))
|
48
|
+
- feat: locales for de [\#903](https://github.com/bensheldon/good_job/pull/903) ([eric-christian](https://github.com/eric-christian))
|
49
|
+
- Update README.md [\#902](https://github.com/bensheldon/good_job/pull/902) ([ain2108](https://github.com/ain2108))
|
50
|
+
- Extract shared methods/scopes into a BaseExecution to share between Execution and Job models [\#894](https://github.com/bensheldon/good_job/pull/894) ([bensheldon](https://github.com/bensheldon))
|
51
|
+
- Add translate\_hash to handle missing translation keys that return hashes; only show translatable/available locales in dropdown [\#891](https://github.com/bensheldon/good_job/pull/891) ([bensheldon](https://github.com/bensheldon))
|
52
|
+
|
3
53
|
## [v3.14.2](https://github.com/bensheldon/good_job/tree/v3.14.2) (2023-03-16)
|
4
54
|
|
5
55
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v3.14.1...v3.14.2)
|
data/README.md
CHANGED
@@ -452,7 +452,7 @@ GoodJob's concurrency control strategy for `perform_limit` is "optimistic retry
|
|
452
452
|
- "Optimistic" meaning that the implementation's performance trade-off assumes that collisions are atypical (e.g. two users enqueue the same job at the same time) rather than regular (e.g. the system enqueues thousands of colliding jobs at the same time). Depending on your concurrency requirements, you may also want to manage concurrency through the number of GoodJob threads and processes that are performing a given queue.
|
453
453
|
- "Retry with an incremental backoff" means that when `perform_limit` is exceeded, the job will raise a `GoodJob::ActiveJobExtensions::Concurrency::ConcurrencyExceededError` which is caught by a `retry_on` handler which re-schedules the job to execute in the near future with an incremental backoff.
|
454
454
|
- First-in-first-out job execution order is not preserved when a job is retried with incremental back-off.
|
455
|
-
- For pessimistic usecases that collisions are expected, use number of threads/processes (e.g., `good_job --
|
455
|
+
- For pessimistic usecases that collisions are expected, use number of threads/processes (e.g., `good_job --queues "serial:1;-serial:5"`) to control concurrency. It is also a good idea to use `perform_limit` as backstop.
|
456
456
|
|
457
457
|
### Cron-style repeating/recurring jobs
|
458
458
|
|
@@ -537,6 +537,7 @@ Batches track a set of jobs, and enqueue an optional callback job when all of th
|
|
537
537
|
- Jobs can be added to an existing batch. Jobs in a batch are enqueued and performed immediately/asynchronously. The final callback job will not be enqueued until `GoodJob::Batch#enqueue` is called.
|
538
538
|
|
539
539
|
```ruby
|
540
|
+
batch = GoodJob::Batch.new
|
540
541
|
batch = GoodJob::Batch.add do
|
541
542
|
10.times { MyJob.perform_later }
|
542
543
|
end
|
@@ -35,7 +35,9 @@ module GoodJob
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def current_locale
|
38
|
-
if
|
38
|
+
if request.GET['locale']
|
39
|
+
request.GET['locale']
|
40
|
+
elsif params[:locale]
|
39
41
|
params[:locale]
|
40
42
|
elsif good_job_available_locales.exclude?(I18n.default_locale) && I18n.available_locales.include?(:en)
|
41
43
|
:en
|
@@ -47,5 +49,6 @@ module GoodJob
|
|
47
49
|
def good_job_available_locales
|
48
50
|
@_good_job_available_locales ||= GoodJob::Engine.root.join("config/locales").glob("*.yml").map { |path| File.basename(path, ".yml").to_sym }.uniq
|
49
51
|
end
|
52
|
+
helper_method :good_job_available_locales
|
50
53
|
end
|
51
54
|
end
|
@@ -15,25 +15,25 @@ module GoodJob
|
|
15
15
|
def enqueue
|
16
16
|
@cron_entry = CronEntry.find(params[:cron_key])
|
17
17
|
@cron_entry.enqueue(Time.current)
|
18
|
-
redirect_back(fallback_location: cron_entries_path, notice: "
|
18
|
+
redirect_back(fallback_location: cron_entries_path, notice: t(".notice"))
|
19
19
|
end
|
20
20
|
|
21
21
|
def enable
|
22
22
|
@cron_entry = CronEntry.find(params[:cron_key])
|
23
23
|
@cron_entry.enable
|
24
|
-
redirect_back(fallback_location: cron_entries_path, notice: "
|
24
|
+
redirect_back(fallback_location: cron_entries_path, notice: t(".notice"))
|
25
25
|
end
|
26
26
|
|
27
27
|
def disable
|
28
28
|
@cron_entry = CronEntry.find(params[:cron_key])
|
29
29
|
@cron_entry.disable
|
30
|
-
redirect_back(fallback_location: cron_entries_path, notice: "
|
30
|
+
redirect_back(fallback_location: cron_entries_path, notice: t(".notice"))
|
31
31
|
end
|
32
32
|
|
33
33
|
private
|
34
34
|
|
35
35
|
def check_settings_migration!
|
36
|
-
redirect_back(fallback_location: cron_entries_path, alert: "
|
36
|
+
redirect_back(fallback_location: cron_entries_path, alert: t("good_job.cron_entries.pending_migrations")) unless GoodJob::Setting.migrated?
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
@@ -62,25 +62,25 @@ module GoodJob
|
|
62
62
|
def discard
|
63
63
|
@job = Job.find(params[:id])
|
64
64
|
@job.discard_job(DISCARD_MESSAGE)
|
65
|
-
redirect_back(fallback_location: jobs_path, notice: "
|
65
|
+
redirect_back(fallback_location: jobs_path, notice: t(".notice"))
|
66
66
|
end
|
67
67
|
|
68
68
|
def reschedule
|
69
69
|
@job = Job.find(params[:id])
|
70
70
|
@job.reschedule_job
|
71
|
-
redirect_back(fallback_location: jobs_path, notice: "
|
71
|
+
redirect_back(fallback_location: jobs_path, notice: t(".notice"))
|
72
72
|
end
|
73
73
|
|
74
74
|
def retry
|
75
75
|
@job = Job.find(params[:id])
|
76
76
|
@job.retry_job
|
77
|
-
redirect_back(fallback_location: jobs_path, notice: "
|
77
|
+
redirect_back(fallback_location: jobs_path, notice: t(".notice"))
|
78
78
|
end
|
79
79
|
|
80
80
|
def destroy
|
81
81
|
@job = Job.find(params[:id])
|
82
82
|
@job.destroy_job
|
83
|
-
redirect_to jobs_path, notice: "
|
83
|
+
redirect_to jobs_path, notice: t(".notice")
|
84
84
|
end
|
85
85
|
|
86
86
|
private
|
@@ -32,7 +32,7 @@ module GoodJob
|
|
32
32
|
|
33
33
|
def job_classes
|
34
34
|
filtered_query(params.slice(:queue_name)).unscope(:select)
|
35
|
-
.group(
|
35
|
+
.group(GoodJob::BaseExecution.params_job_class).count
|
36
36
|
.sort_by { |name, _count| name.to_s }
|
37
37
|
.to_h
|
38
38
|
end
|
@@ -19,7 +19,7 @@ module GoodJob
|
|
19
19
|
|
20
20
|
def relative_time(timestamp, **options)
|
21
21
|
options = options.reverse_merge({ scope: "good_job.datetime.distance_in_words" })
|
22
|
-
text = timestamp.future? ?
|
22
|
+
text = t("good_job.helpers.relative_time.#{timestamp.future? ? 'future' : 'past'}", time: time_ago_in_words(timestamp, **options))
|
23
23
|
tag.time(text, datetime: timestamp, title: timestamp)
|
24
24
|
end
|
25
25
|
|
@@ -42,7 +42,7 @@ module GoodJob
|
|
42
42
|
}.freeze
|
43
43
|
|
44
44
|
def status_badge(status)
|
45
|
-
content_tag :span, status_icon(status, class: "text-white") + t(status, scope: 'good_job.status'),
|
45
|
+
content_tag :span, status_icon(status, class: "text-white") + t(status, scope: 'good_job.status', count: 1),
|
46
46
|
class: "badge rounded-pill bg-#{STATUS_COLOR.fetch(status)} d-inline-flex gap-2 ps-1 pe-3 align-items-center"
|
47
47
|
end
|
48
48
|
|
@@ -57,5 +57,14 @@ module GoodJob
|
|
57
57
|
partial = lookup_context.find_template("good_job/shared/icons/#{name}", [], true)
|
58
58
|
partial.render(self, {})
|
59
59
|
end
|
60
|
+
|
61
|
+
def translate_hash(key, **options)
|
62
|
+
translation_exists?(key, **options) ? translate(key, **options) : {}
|
63
|
+
end
|
64
|
+
|
65
|
+
def translation_exists?(key, **options)
|
66
|
+
true if good_job_available_locales.include?(I18n.locale)
|
67
|
+
I18n.exists?(scope_key_by_partial(key), **options)
|
68
|
+
end
|
60
69
|
end
|
61
70
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GoodJob
|
4
|
+
# ActiveRecord model to share behavior between {Job} and {Execution} models
|
5
|
+
# which both read out of the same table.
|
6
|
+
class BaseExecution < BaseRecord
|
7
|
+
self.table_name = 'good_jobs'
|
8
|
+
|
9
|
+
# With a given class name
|
10
|
+
# @!method job_class
|
11
|
+
# @!scope class
|
12
|
+
# @param string [String] Execution class name
|
13
|
+
# @return [ActiveRecord::Relation]
|
14
|
+
scope :job_class, ->(name) { where(params_job_class.eq(name)) }
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def json_string(json, attr)
|
18
|
+
Arel::Nodes::Grouping.new(Arel::Nodes::InfixOperation.new('->>', json, Arel::Nodes.build_quoted(attr)))
|
19
|
+
end
|
20
|
+
|
21
|
+
def params_job_class
|
22
|
+
json_string(arel_table['serialized_params'], 'job_class')
|
23
|
+
end
|
24
|
+
|
25
|
+
def params_execution_count
|
26
|
+
Arel::Nodes::InfixOperation.new(
|
27
|
+
'::',
|
28
|
+
json_string(arel_table['serialized_params'], 'executions'),
|
29
|
+
Arel.sql('integer')
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def coalesce_scheduled_at_created_at
|
34
|
+
arel_table.coalesce(arel_table['scheduled_at'], arel_table['created_at'])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# The ActiveJob job class, as a string
|
39
|
+
# @return [String]
|
40
|
+
def job_class
|
41
|
+
serialized_params['job_class']
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GoodJob
|
3
3
|
# ActiveRecord model that represents an +ActiveJob+ job.
|
4
|
-
class Execution <
|
4
|
+
class Execution < BaseExecution
|
5
5
|
include Lockable
|
6
6
|
include Filterable
|
7
7
|
include Reportable
|
@@ -82,14 +82,6 @@ module GoodJob
|
|
82
82
|
# @return [ActiveRecord::Relation]
|
83
83
|
scope :active_job_id, ->(active_job_id) { where(active_job_id: active_job_id) }
|
84
84
|
|
85
|
-
# Get executions with given class name
|
86
|
-
# @!method job_class
|
87
|
-
# @!scope class
|
88
|
-
# @param string [String]
|
89
|
-
# Execution class name
|
90
|
-
# @return [ActiveRecord::Relation]
|
91
|
-
scope :job_class, ->(job_class) { where("serialized_params->>'job_class' = ?", job_class) }
|
92
|
-
|
93
85
|
# Get executions that have not yet finished (succeeded or discarded).
|
94
86
|
# @!method unfinished
|
95
87
|
# @!scope class
|
@@ -119,7 +111,7 @@ module GoodJob
|
|
119
111
|
# @!method creation_ordered
|
120
112
|
# @!scope class
|
121
113
|
# @return [ActiveRecord:Relation]
|
122
|
-
scope :creation_ordered, -> { order(
|
114
|
+
scope :creation_ordered, -> { order(created_at: :asc) }
|
123
115
|
|
124
116
|
# Order executions for de-queueing
|
125
117
|
# @!method dequeueing_ordered
|
@@ -155,7 +147,7 @@ module GoodJob
|
|
155
147
|
# @!method schedule_ordered
|
156
148
|
# @!scope class
|
157
149
|
# @return [ActiveRecord::Relation]
|
158
|
-
scope :schedule_ordered, -> { order(
|
150
|
+
scope :schedule_ordered, -> { order(coalesce_scheduled_at_created_at.asc) }
|
159
151
|
|
160
152
|
# Get Jobs were completed before the given timestamp. If no timestamp is
|
161
153
|
# provided, get all jobs that have been completed. By default, GoodJob
|
data/app/models/good_job/job.rb
CHANGED
@@ -5,7 +5,7 @@ module GoodJob
|
|
5
5
|
# The +good_jobs+ table is a table of individual {GoodJob::Execution}s that share the same +active_job_id+.
|
6
6
|
# A single row from the +good_jobs+ table of executions is fetched to represent a Job.
|
7
7
|
#
|
8
|
-
class Job <
|
8
|
+
class Job < BaseExecution
|
9
9
|
include Filterable
|
10
10
|
include Lockable
|
11
11
|
include Reportable
|
@@ -23,26 +23,6 @@ module GoodJob
|
|
23
23
|
def table_name=(_value)
|
24
24
|
raise NotImplementedError, 'Assign GoodJob::Execution.table_name directly'
|
25
25
|
end
|
26
|
-
|
27
|
-
def json_string(json, attr)
|
28
|
-
Arel::Nodes::Grouping.new(Arel::Nodes::InfixOperation.new('->>', json, Arel::Nodes.build_quoted(attr)))
|
29
|
-
end
|
30
|
-
|
31
|
-
def params_job_class
|
32
|
-
json_string(arel_table['serialized_params'], 'job_class')
|
33
|
-
end
|
34
|
-
|
35
|
-
def params_execution_count
|
36
|
-
Arel::Nodes::InfixOperation.new(
|
37
|
-
'::',
|
38
|
-
json_string(arel_table['serialized_params'], 'executions'),
|
39
|
-
Arel.sql('integer')
|
40
|
-
)
|
41
|
-
end
|
42
|
-
|
43
|
-
def coalesce_scheduled_at_created_at
|
44
|
-
arel_table.coalesce(arel_table['scheduled_at'], arel_table['created_at'])
|
45
|
-
end
|
46
26
|
end
|
47
27
|
|
48
28
|
self.primary_key = 'active_job_id'
|
@@ -54,13 +34,6 @@ module GoodJob
|
|
54
34
|
# Only the most-recent unretried execution represents a "Job"
|
55
35
|
default_scope { where(retried_good_job_id: nil) }
|
56
36
|
|
57
|
-
# Get Jobs with given class name
|
58
|
-
# @!method job_class
|
59
|
-
# @!scope class
|
60
|
-
# @param string [String] Execution class name
|
61
|
-
# @return [ActiveRecord::Relation]
|
62
|
-
scope :job_class, ->(name) { where(params_job_class.eq(name)) }
|
63
|
-
|
64
37
|
# Get Jobs finished before the given timestamp.
|
65
38
|
# @!method finished_before(timestamp)
|
66
39
|
# @!scope class
|
@@ -89,12 +62,6 @@ module GoodJob
|
|
89
62
|
active_job_id
|
90
63
|
end
|
91
64
|
|
92
|
-
# The ActiveJob job class, as a string
|
93
|
-
# @return [String]
|
94
|
-
def job_class
|
95
|
-
serialized_params['job_class']
|
96
|
-
end
|
97
|
-
|
98
65
|
# Override #reload to add a custom scope to ensure the reloaded record is the head execution
|
99
66
|
# @return [Job]
|
100
67
|
def reload(options = nil)
|
@@ -2,10 +2,10 @@
|
|
2
2
|
<div class="list-group list-group-flush text-nowrap table-jobs" role="table">
|
3
3
|
<header class="list-group-item bg-light">
|
4
4
|
<div class="row small text-muted text-uppercase align-items-center">
|
5
|
-
|
6
|
-
<div class="d-none d-lg-block col-lg-1 text-lg-center"
|
7
|
-
<div class="d-none d-lg-block col-lg-1 text-lg-end"
|
8
|
-
<div class="d-none d-lg-block col-lg-1 text-lg-end"
|
5
|
+
<div class="col-4"><%=t "good_job.models.batch.jobs" %></div>
|
6
|
+
<div class="d-none d-lg-block col-lg-1 text-lg-center"><%=t "good_job.models.job.queue" %></div>
|
7
|
+
<div class="d-none d-lg-block col-lg-1 text-lg-end"><%=t "good_job.models.job.priority" %></div>
|
8
|
+
<div class="d-none d-lg-block col-lg-1 text-lg-end"><%=t "good_job.models.job.attempts" %></div>
|
9
9
|
<div class="col text-end">
|
10
10
|
<%= tag.button type: "button", class: "btn btn-sm text-muted", role: "button",
|
11
11
|
data: { bs_toggle: "collapse", bs_target: ".job-params" },
|
@@ -26,15 +26,15 @@
|
|
26
26
|
<%= tag.h5 tag.code(link_to(job.job_class, job_path(job), class: "text-reset text-decoration-none")), class: "text-reset mb-0" %>
|
27
27
|
</div>
|
28
28
|
<div class="col-4 col-lg-1 text-lg-center">
|
29
|
-
<div class="d-lg-none small text-muted mt-1"
|
29
|
+
<div class="d-lg-none small text-muted mt-1"><%=t "good_job.models.job.queue" %></div>
|
30
30
|
<span class="badge bg-primary bg-opacity-25 text-dark font-monospace"><%= job.queue_name %></span>
|
31
31
|
</div>
|
32
32
|
<div class="col-4 col-lg-1 text-lg-end">
|
33
|
-
<div class="d-lg-none small text-muted mt-1"
|
33
|
+
<div class="d-lg-none small text-muted mt-1"><%=t "good_job.models.job.priority" %>Priority</div>
|
34
34
|
<span class="font-monospace fw-bold"><%= job.priority %></span>
|
35
35
|
</div>
|
36
36
|
<div class="col-4 col-lg-1 text-lg-end">
|
37
|
-
<div class="d-lg-none small text-muted mt-1"
|
37
|
+
<div class="d-lg-none small text-muted mt-1"><%=t "good_job.models.job.attempts" %></div>
|
38
38
|
<% if job.executions_count > 0 && job.status != :finished %>
|
39
39
|
<%= tag.span job.executions_count, class: "badge rounded-pill bg-danger", data: {
|
40
40
|
bs_toggle: "popover",
|
@@ -53,33 +53,33 @@
|
|
53
53
|
<div class="dropdown float-end">
|
54
54
|
<button class="d-flex align-items-center btn btn-sm" type="button" id="<%= dom_id(job, :actions) %>" data-bs-toggle="dropdown" aria-expanded="false">
|
55
55
|
<%= render "good_job/shared/icons/dots" %>
|
56
|
-
<span class="visually-hidden"
|
56
|
+
<span class="visually-hidden"><%=t ".actions.title" %></span>
|
57
57
|
</button>
|
58
58
|
<ul class="dropdown-menu shadow" aria-labelledby="<%= dom_id(job, :actions) %>">
|
59
59
|
<li>
|
60
60
|
<% job_reschedulable = job.status.in? [:scheduled, :retried, :queued] %>
|
61
|
-
<%= link_to reschedule_job_path(job.id), method: :put, class: "dropdown-item #{'disabled' unless job_reschedulable}", title: "
|
61
|
+
<%= link_to reschedule_job_path(job.id), method: :put, class: "dropdown-item #{'disabled' unless job_reschedulable}", title: t(".actions.reschedule"), data: { confirm: t(".actions.confirm_reschedule"), disable: true } do %>
|
62
62
|
<%= render "good_job/shared/icons/skip_forward" %>
|
63
|
-
|
63
|
+
<%=t "good_job.actions.reschedule" %>
|
64
64
|
<% end %>
|
65
65
|
</li>
|
66
66
|
<li>
|
67
67
|
<% job_discardable = job.status.in? [:scheduled, :retried, :queued] %>
|
68
|
-
<%= link_to discard_job_path(job.id), method: :put, class: "dropdown-item #{'disabled' unless job_discardable}", title: "
|
68
|
+
<%= link_to discard_job_path(job.id), method: :put, class: "dropdown-item #{'disabled' unless job_discardable}", title: t(".actions.discard"), data: { confirm: t(".actions.confirm_discard"), disable: true } do %>
|
69
69
|
<%= render "good_job/shared/icons/stop" %>
|
70
|
-
|
70
|
+
<%=t "good_job.actions.discard" %>
|
71
71
|
<% end %>
|
72
72
|
</li>
|
73
73
|
<li>
|
74
|
-
<%= link_to retry_job_path(job.id), method: :put, class: "dropdown-item #{'disabled' unless job.status == :discarded}", title: "
|
74
|
+
<%= link_to retry_job_path(job.id), method: :put, class: "dropdown-item #{'disabled' unless job.status == :discarded}", title: t(".actions.retry"), data: { confirm: t(".actions.confirm_retry"), disable: true } do %>
|
75
75
|
<%= render "good_job/shared/icons/arrow_clockwise" %>
|
76
|
-
|
76
|
+
<%=t "good_job.actions.retry" %>
|
77
77
|
<% end %>
|
78
78
|
</li>
|
79
79
|
<li>
|
80
|
-
<%= link_to job_path(job.id), method: :delete, class: "dropdown-item #{'disabled' unless job.status.in? [:discarded, :finished]}", title: "
|
80
|
+
<%= link_to job_path(job.id), method: :delete, class: "dropdown-item #{'disabled' unless job.status.in? [:discarded, :finished]}", title: t(".actions.destroy"), data: { confirm: t(".actions.confirm_destroy"), disable: true } do %>
|
81
81
|
<%= render_icon "trash" %>
|
82
|
-
|
82
|
+
<%=t "good_job.actions.destroy" %>
|
83
83
|
<% end %>
|
84
84
|
</li>
|
85
85
|
|
@@ -89,7 +89,7 @@
|
|
89
89
|
data: { bs_toggle: "collapse" },
|
90
90
|
aria: { expanded: false, controls: dom_id(job, "params") } do %>
|
91
91
|
<%= render_icon "info" %>
|
92
|
-
|
92
|
+
<%=t "good_job.actions.inspect" %>
|
93
93
|
<% end %>
|
94
94
|
</li>
|
95
95
|
</ul>
|
@@ -103,7 +103,7 @@
|
|
103
103
|
<% end %>
|
104
104
|
<% else %>
|
105
105
|
<div class="list-group-item py-4 text-center text-muted">
|
106
|
-
|
106
|
+
<%=t ".no_jobs_found" %>
|
107
107
|
</div>
|
108
108
|
<% end %>
|
109
109
|
</div>
|
@@ -2,18 +2,18 @@
|
|
2
2
|
<div class="list-group list-group-flush text-nowrap table-batches" role="table">
|
3
3
|
<header class="list-group-item bg-light">
|
4
4
|
<div class="row small text-muted text-uppercase align-items-center">
|
5
|
-
<div class="col-4"
|
6
|
-
<div class="col-lg-1 d-none d-lg-block"
|
7
|
-
<div class="col-lg-1 d-none d-lg-block"
|
8
|
-
<div class="col-lg-1 d-none d-lg-block"
|
9
|
-
<div class="col-lg-1 d-none d-lg-block"
|
10
|
-
<div class="col-lg-1 d-none d-lg-block"
|
5
|
+
<div class="col-4"><%=t "good_job.models.batch.name" %></div>
|
6
|
+
<div class="col-lg-1 d-none d-lg-block"><%=t "good_job.models.batch.created" %></div>
|
7
|
+
<div class="col-lg-1 d-none d-lg-block"><%=t "good_job.models.batch.enqueued" %></div>
|
8
|
+
<div class="col-lg-1 d-none d-lg-block"><%=t "good_job.models.batch.discarded" %></div>
|
9
|
+
<div class="col-lg-1 d-none d-lg-block"><%=t "good_job.models.batch.finished" %></div>
|
10
|
+
<div class="col-lg-1 d-none d-lg-block"><%=t "good_job.models.batch.jobs" %></div>
|
11
11
|
<div class="col text-end">
|
12
12
|
<%= tag.button type: "button", class: "btn btn-sm text-muted", role: "button",
|
13
13
|
data: { bs_toggle: "collapse", bs_target: ".batch-properties" },
|
14
14
|
aria: { expanded: false, controls: batches.map { |batch| "##{dom_id(batch, "params")}" }.join(" ") } do %>
|
15
15
|
<%= render_icon "info" %>
|
16
|
-
<span class="visually-hidden"
|
16
|
+
<span class="visually-hidden"><%=t "good_job.actions.inspect" %></span>
|
17
17
|
<% end %>
|
18
18
|
</div>
|
19
19
|
</div>
|
@@ -33,38 +33,38 @@
|
|
33
33
|
<% end %>
|
34
34
|
</div>
|
35
35
|
<div class="col-6 col-lg-1 text-wrap">
|
36
|
-
<div class="d-lg-none small text-muted mt-1"
|
36
|
+
<div class="d-lg-none small text-muted mt-1"><%=t "good_job.models.batch.created_at" %></div>
|
37
37
|
<%= relative_time(batch.created_at) %>
|
38
38
|
</div>
|
39
39
|
<div class="col-6 col-lg-1 text-wrap">
|
40
40
|
<% if batch.enqueued_at %>
|
41
|
-
<div class="d-lg-none small text-muted mt-1"
|
41
|
+
<div class="d-lg-none small text-muted mt-1"><%=t "good_job.models.batch.enqueued_at" %></div>
|
42
42
|
<%= relative_time(batch.enqueued_at) %>
|
43
43
|
<% end %>
|
44
44
|
</div>
|
45
45
|
<div class="col-6 col-lg-1 text-wrap">
|
46
46
|
<% if batch.discarded_at %>
|
47
|
-
<div class="d-lg-none small text-muted mt-1"
|
47
|
+
<div class="d-lg-none small text-muted mt-1"><%=t "good_job.models.batch.discarded_at" %></div>
|
48
48
|
<%= relative_time(batch.discarded_at) %>
|
49
49
|
<% end %>
|
50
50
|
</div>
|
51
51
|
<div class="col-6 col-lg-1 text-wrap">
|
52
52
|
<% if batch.finished_at %>
|
53
|
-
<div class="d-lg-none small text-muted mt-1"
|
53
|
+
<div class="d-lg-none small text-muted mt-1"><%=t "good_job.models.batch.finished_at" %></div>
|
54
54
|
<%= relative_time(batch.finished_at) %>
|
55
55
|
<% end %>
|
56
56
|
</div>
|
57
57
|
<div class="col-6 col-lg-1">
|
58
|
-
<div class="d-lg-none small text-muted mt-1"
|
58
|
+
<div class="d-lg-none small text-muted mt-1"><%=t "good_job.models.batch.jobs" %></div>
|
59
59
|
<%= batch.jobs.count %>
|
60
60
|
</div>
|
61
61
|
<div class="col text-end">
|
62
62
|
<%= tag.button type: "button", class: "btn btn-sm text-muted", role: "button",
|
63
|
-
title: "
|
63
|
+
title: t("good_job.actions.inspect"),
|
64
64
|
data: { bs_toggle: "collapse", bs_target: "##{dom_id(batch, 'properties')}" },
|
65
65
|
aria: { expanded: false, controls: dom_id(batch, "state") } do %>
|
66
66
|
<%= render_icon "info" %>
|
67
|
-
<span class="visually-hidden"
|
67
|
+
<span class="visually-hidden"><%=t "good_job.actions.inspect" %></span>
|
68
68
|
<% end %>
|
69
69
|
</div>
|
70
70
|
</div>
|
@@ -75,7 +75,7 @@
|
|
75
75
|
<% end %>
|
76
76
|
<% else %>
|
77
77
|
<div class="list-group-item py-4 text-center text-muted">
|
78
|
-
|
78
|
+
<%=t ".no_batches_found" %>
|
79
79
|
</div>
|
80
80
|
<% end %>
|
81
81
|
</div>
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<div class="border-bottom">
|
2
|
-
<h2 class="pt-3 pb-2"
|
2
|
+
<h2 class="pt-3 pb-2"><%= t ".title" %></h2>
|
3
3
|
</div>
|
4
4
|
|
5
5
|
<% if GoodJob::BatchRecord.migrated? %>
|
@@ -9,12 +9,12 @@
|
|
9
9
|
<ul class="pagination">
|
10
10
|
<li class="page-item">
|
11
11
|
<%= link_to(@filter.to_params(after_created_at: @filter.last.created_at, after_id: @filter.last.id), class: "page-link") do %>
|
12
|
-
|
12
|
+
<%= t ".older_batches" %> <span aria-hidden="true">»</span>
|
13
13
|
<% end %>
|
14
14
|
</li>
|
15
15
|
</ul>
|
16
16
|
</nav>
|
17
17
|
<% end %>
|
18
18
|
<% else %>
|
19
|
-
<h3 class="text-center my-5"
|
19
|
+
<h3 class="text-center my-5"><%= t ".pending_migrations" %></h3>
|
20
20
|
<% end %>
|
@@ -4,7 +4,7 @@
|
|
4
4
|
<div class="col">
|
5
5
|
<nav aria-label="breadcrumb">
|
6
6
|
<ol class="breadcrumb small mb-0">
|
7
|
-
<li class="breadcrumb-item"><%= link_to "
|
7
|
+
<li class="breadcrumb-item"><%= link_to t("good_job.batches.index.title"), batches_path %></li>
|
8
8
|
<li class="breadcrumb-item active" aria-current="page"><%= tag.code @batch.id, class: "text-muted" %></li>
|
9
9
|
</ol>
|
10
10
|
<h2 class="h5 mt-2"><%= @batch.description %></h2>
|
@@ -15,18 +15,18 @@
|
|
15
15
|
</div>
|
16
16
|
|
17
17
|
<div class="my-4">
|
18
|
-
<h5
|
18
|
+
<h5><%= t ".attributes" %></h5>
|
19
19
|
<div class="bg-dark text-light p-3 rounded">
|
20
20
|
<%= tag.pre JSON.pretty_generate @batch.display_attributes, class: 'text-wrap text-break' %>
|
21
21
|
</div>
|
22
22
|
</div>
|
23
23
|
|
24
24
|
<div class="my-4">
|
25
|
-
<h5
|
25
|
+
<h5><%= t ".callback_jobs" %></h5>
|
26
26
|
<%= render 'jobs', jobs: @batch.callback_jobs.reverse %>
|
27
27
|
</div>
|
28
28
|
|
29
29
|
<div class="my-4">
|
30
|
-
<h5
|
30
|
+
<h5><%= t ".batched_jobs" %></h5>
|
31
31
|
<%= render 'jobs', jobs: @batch.jobs.reverse %>
|
32
32
|
</div>
|