good_job 4.9.0 → 4.9.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 +22 -0
- data/README.md +1 -1
- data/app/filters/good_job/base_filter.rb +20 -4
- data/app/filters/good_job/batches_filter.rb +4 -9
- data/app/filters/good_job/jobs_filter.rb +13 -0
- data/app/models/concerns/good_job/filterable.rb +16 -10
- data/app/models/good_job/batch_record.rb +1 -14
- data/app/views/good_job/batches/index.html.erb +1 -1
- data/app/views/good_job/jobs/_table.erb +1 -1
- data/app/views/good_job/jobs/index.html.erb +1 -1
- data/app/views/good_job/shared/_filter.erb +1 -1
- data/lib/generators/good_job/templates/install/migrations/create_good_jobs.rb.erb +1 -0
- data/lib/generators/good_job/templates/update/migrations/03_add_index_good_jobs_concurrency_key_created_at.rb.erb +17 -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: 257efee85262d3d49be021082bc73cce8dfcf2bea117841a31862bb592158593
|
4
|
+
data.tar.gz: d5adc70dcd2894ce5190e07eab45e322c7724f74d96f5a4ccf96bee3c1b35798
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 003cb3656a88bcd02e8354e315dff667a284d3cae0674ff8b5f73a7cbcfd0ed1b60faf27ff23b14a1d83e395209d4292cfb8e6d771835c4a9418c8ff1977b327
|
7
|
+
data.tar.gz: c13483d1ac9f15a720b161905cab041f2c52f7305568b885bfeb0c7fbc514662023cde9ff87fe09f99811536285265aa3d3a4aa31113f73c026f1d39a5521b88
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v4.9.1](https://github.com/bensheldon/good_job/tree/v4.9.1) (2025-03-09)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/bensheldon/good_job/compare/v4.9.0...v4.9.1)
|
6
|
+
|
7
|
+
**Implemented enhancements:**
|
8
|
+
|
9
|
+
- Order Dashboard jobs in more "natural" order [\#1604](https://github.com/bensheldon/good_job/pull/1604) ([francois](https://github.com/francois))
|
10
|
+
|
11
|
+
**Fixed bugs:**
|
12
|
+
|
13
|
+
- \[dashboard\] Scheduled tasks are shown "backwards" [\#1580](https://github.com/bensheldon/good_job/issues/1580)
|
14
|
+
- Update `form_with` calls to be compatible with Rails 8 [\#1610](https://github.com/bensheldon/good_job/pull/1610) ([sallyhall](https://github.com/sallyhall))
|
15
|
+
- Add index on good\_jobs: \[:concurrency\_key, :created\_at\] to improve performance of throttling \(\#1603\) [\#1605](https://github.com/bensheldon/good_job/pull/1605) ([Intrepidd](https://github.com/Intrepidd))
|
16
|
+
|
17
|
+
**Closed issues:**
|
18
|
+
|
19
|
+
- Cron did not enqueue jobs [\#1600](https://github.com/bensheldon/good_job/issues/1600)
|
20
|
+
- Same job performed by all threads [\#1599](https://github.com/bensheldon/good_job/issues/1599)
|
21
|
+
- Option for bin/rails g good\_job:install to purge Solid gems [\#1593](https://github.com/bensheldon/good_job/issues/1593)
|
22
|
+
- Jobs are not being picked up at the expected rate [\#1578](https://github.com/bensheldon/good_job/issues/1578)
|
23
|
+
- Question about GoodJob Batches in tests [\#1479](https://github.com/bensheldon/good_job/issues/1479)
|
24
|
+
|
3
25
|
## [v4.9.0](https://github.com/bensheldon/good_job/tree/v4.9.0) (2025-02-07)
|
4
26
|
|
5
27
|
[Full Changelog](https://github.com/bensheldon/good_job/compare/v4.8.2...v4.9.0)
|
data/README.md
CHANGED
@@ -1032,7 +1032,7 @@ To detect the start of a graceful shutdown from within a performing job, for exa
|
|
1032
1032
|
```ruby
|
1033
1033
|
def perform(lots_of_records)
|
1034
1034
|
lots_of_records.each do |record|
|
1035
|
-
break if GoodJob.current_thread_shutting_down? # or `unless GoodJob.
|
1035
|
+
break if GoodJob.current_thread_shutting_down? # or `unless GoodJob.current_thread_running?`
|
1036
1036
|
# process record ...
|
1037
1037
|
end
|
1038
1038
|
end
|
@@ -13,12 +13,15 @@ module GoodJob
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def records
|
16
|
-
|
16
|
+
after_at = params[:after_at].present? ? Time.zone.parse(params[:after_at]) : nil
|
17
|
+
after_id = params[:after_id] if after_at
|
18
|
+
limit = params.fetch(:limit, DEFAULT_LIMIT)
|
17
19
|
|
18
20
|
query_for_records.display_all(
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
ordered_by: ordered_by,
|
22
|
+
after_at: after_at,
|
23
|
+
after_id: after_id
|
24
|
+
).limit(limit)
|
22
25
|
end
|
23
26
|
|
24
27
|
def last
|
@@ -66,6 +69,19 @@ module GoodJob
|
|
66
69
|
filtered_query.count
|
67
70
|
end
|
68
71
|
|
72
|
+
def ordered_by
|
73
|
+
%w[created_at desc]
|
74
|
+
end
|
75
|
+
|
76
|
+
def next_page_params
|
77
|
+
order_column = ordered_by.first
|
78
|
+
|
79
|
+
{
|
80
|
+
after_at: records.last&.send(order_column),
|
81
|
+
after_id: records.last&.id,
|
82
|
+
}.merge(to_params)
|
83
|
+
end
|
84
|
+
|
69
85
|
private
|
70
86
|
|
71
87
|
def query_for_records
|
@@ -2,19 +2,14 @@
|
|
2
2
|
|
3
3
|
module GoodJob
|
4
4
|
class BatchesFilter < BaseFilter
|
5
|
-
def records
|
6
|
-
after_created_at = params[:after_created_at].present? ? Time.zone.parse(params[:after_created_at]) : nil
|
7
|
-
|
8
|
-
filtered_query.display_all(
|
9
|
-
after_created_at: after_created_at,
|
10
|
-
after_id: params[:after_id]
|
11
|
-
).limit(params.fetch(:limit, DEFAULT_LIMIT))
|
12
|
-
end
|
13
|
-
|
14
5
|
def filtered_query(_filtered_params = params)
|
15
6
|
base_query
|
16
7
|
end
|
17
8
|
|
9
|
+
def query_for_records
|
10
|
+
default_base_query
|
11
|
+
end
|
12
|
+
|
18
13
|
def default_base_query
|
19
14
|
GoodJob::BatchRecord.includes(:jobs)
|
20
15
|
end
|
@@ -53,6 +53,19 @@ module GoodJob
|
|
53
53
|
@_filtered_count ||= filtered_query.unscope(:select).count
|
54
54
|
end
|
55
55
|
|
56
|
+
def ordered_by
|
57
|
+
case params[:state]
|
58
|
+
when "scheduled", "retried", "pending", "queued"
|
59
|
+
%w[scheduled_at asc]
|
60
|
+
when "running"
|
61
|
+
%w[performed_at desc]
|
62
|
+
when "finished", "discarded"
|
63
|
+
%w[finished_at desc]
|
64
|
+
else
|
65
|
+
%w[created_at desc]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
56
69
|
private
|
57
70
|
|
58
71
|
def query_for_records
|
@@ -7,21 +7,27 @@ module GoodJob
|
|
7
7
|
|
8
8
|
included do
|
9
9
|
# Get records in display order with optional keyset pagination.
|
10
|
-
# @!method display_all(
|
10
|
+
# @!method display_all(ordered_by: ["created_at", "desc"], after_at: nil, after_id: nil)
|
11
11
|
# @!scope class
|
12
|
-
# @param
|
13
|
-
#
|
12
|
+
# @param ordered_by [Array<String>]
|
13
|
+
# Order to display records, from Filter#ordered_by
|
14
|
+
# @param after_at [DateTime, String, nil]
|
15
|
+
# Display records after this time for keyset pagination
|
14
16
|
# @param after_id [Numeric, String, nil]
|
15
17
|
# Display records after this ID for keyset pagination
|
16
18
|
# @return [ActiveRecord::Relation]
|
17
|
-
scope :display_all, (lambda do |
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
query = query.where arel_table[
|
19
|
+
scope :display_all, (lambda do |ordered_by: %w[created_at desc], after_at: nil, after_id: nil|
|
20
|
+
order_column, order_direction = ordered_by
|
21
|
+
query = self
|
22
|
+
|
23
|
+
if after_at.present? && after_id.present?
|
24
|
+
query = query.where Arel::Nodes::Grouping.new([arel_table[order_column], arel_table[primary_key]]).send(
|
25
|
+
order_direction == 'asc' ? :gteq : :lt,
|
26
|
+
Arel::Nodes::Grouping.new([bind_value(order_column, after_at, ActiveRecord::Type::DateTime), bind_value(primary_key, after_id, ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Uuid)])
|
27
|
+
)
|
23
28
|
end
|
24
|
-
|
29
|
+
|
30
|
+
query.order Arel.sql("#{order_column} #{order_direction}, #{primary_key} #{order_direction}")
|
25
31
|
end)
|
26
32
|
|
27
33
|
# Search records by text query.
|
@@ -5,6 +5,7 @@ require 'active_job/arguments'
|
|
5
5
|
module GoodJob
|
6
6
|
class BatchRecord < BaseRecord
|
7
7
|
include AdvisoryLockable
|
8
|
+
include Filterable
|
8
9
|
|
9
10
|
self.table_name = 'good_job_batches'
|
10
11
|
self.implicit_order_column = 'created_at'
|
@@ -24,20 +25,6 @@ module GoodJob
|
|
24
25
|
alias_attribute :discarded?, :discarded_at
|
25
26
|
alias_attribute :finished?, :finished_at
|
26
27
|
|
27
|
-
scope :display_all, (lambda do |after_created_at: nil, after_id: nil|
|
28
|
-
query = order(created_at: :desc, id: :desc)
|
29
|
-
if after_created_at.present? && after_id.present?
|
30
|
-
query = if Gem::Version.new(Rails.version) < Gem::Version.new('7.0.0.a') || Concurrent.on_jruby?
|
31
|
-
query.where(Arel.sql('(created_at, id) < (:after_created_at, :after_id)'), after_created_at: after_created_at, after_id: after_id)
|
32
|
-
else
|
33
|
-
query.where Arel::Nodes::Grouping.new([arel_table["created_at"], arel_table["id"]]).lt(Arel::Nodes::Grouping.new([bind_value('created_at', after_created_at, ActiveRecord::Type::DateTime), bind_value('id', after_id, ActiveRecord::Type::String)]))
|
34
|
-
end
|
35
|
-
elsif after_created_at.present?
|
36
|
-
query = query.where arel_table["created_at"].lt(bind_value('created_at', after_created_at, ActiveRecord::Type::DateTime))
|
37
|
-
end
|
38
|
-
query
|
39
|
-
end)
|
40
|
-
|
41
28
|
def self.jobs_finished_at_migrated?
|
42
29
|
column_names.include?('jobs_finished_at')
|
43
30
|
end
|
@@ -7,7 +7,7 @@
|
|
7
7
|
<nav aria-label="Batch pagination" class="mt-3">
|
8
8
|
<ul class="pagination">
|
9
9
|
<li class="page-item">
|
10
|
-
<%= link_to(@filter.
|
10
|
+
<%= link_to(@filter.next_page_params, class: "page-link") do %>
|
11
11
|
<%= t ".older_batches" %> <span aria-hidden="true">»</span>
|
12
12
|
<% end %>
|
13
13
|
</li>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<%= form_with(url: mass_update_jobs_path(filter.to_params), method: :put, local: true, data: { "checkbox-toggle": "job_ids" }) do |form| %>
|
1
|
+
<%= form_with(model: false, url: mass_update_jobs_path(filter.to_params), method: :put, local: true, data: { "checkbox-toggle": "job_ids" }) do |form| %>
|
2
2
|
<div class="my-3 card" data-gj-poll-replace id="jobs-table">
|
3
3
|
<div class="list-group list-group-flush text-nowrap table-jobs" role="table">
|
4
4
|
<header class="list-group-item bg-body-tertiary">
|
@@ -7,7 +7,7 @@
|
|
7
7
|
<nav aria-label="<%= t ".job_pagination" %>" class="mt-3">
|
8
8
|
<ul class="pagination">
|
9
9
|
<li class="page-item">
|
10
|
-
<%= link_to(@filter.
|
10
|
+
<%= link_to(@filter.next_page_params, class: "page-link") do %>
|
11
11
|
<%= t ".older_jobs" %> <span aria-hidden="true">»</span>
|
12
12
|
<% end %>
|
13
13
|
</li>
|
@@ -4,7 +4,7 @@
|
|
4
4
|
<h2 class="pt-3 pb-2"><%= title %></h2>
|
5
5
|
</div>
|
6
6
|
|
7
|
-
<%= form_with(url: "", method: :get, local: true, id: "filter_form", class: "") do |form| %>
|
7
|
+
<%= form_with(model: false, url: "", method: :get, local: true, id: "filter_form", class: "") do |form| %>
|
8
8
|
<%= hidden_field_tag :poll, params[:poll] %>
|
9
9
|
<%= hidden_field_tag :state, params[:state] %>
|
10
10
|
<%= hidden_field_tag :locale, params[:locale] if params[:locale] %>
|
@@ -82,6 +82,7 @@ class CreateGoodJobs < ActiveRecord::Migration<%= migration_version %>
|
|
82
82
|
add_index :good_jobs, [:queue_name, :scheduled_at], where: "(finished_at IS NULL)", name: :index_good_jobs_on_queue_name_and_scheduled_at
|
83
83
|
add_index :good_jobs, [:active_job_id, :created_at], name: :index_good_jobs_on_active_job_id_and_created_at
|
84
84
|
add_index :good_jobs, :concurrency_key, where: "(finished_at IS NULL)", name: :index_good_jobs_on_concurrency_key_when_unfinished
|
85
|
+
add_index :good_jobs, [:concurrency_key, :created_at], name: :index_good_jobs_on_concurrency_key_and_created_at
|
85
86
|
add_index :good_jobs, [:cron_key, :created_at], where: "(cron_key IS NOT NULL)", name: :index_good_jobs_on_cron_key_and_created_at_cond
|
86
87
|
add_index :good_jobs, [:cron_key, :cron_at], where: "(cron_key IS NOT NULL)", unique: true, name: :index_good_jobs_on_cron_key_and_cron_at_cond
|
87
88
|
add_index :good_jobs, [:finished_at], where: "retried_good_job_id IS NULL AND finished_at IS NOT NULL", name: :index_good_jobs_jobs_on_finished_at
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddIndexGoodJobsConcurrencyKeyCreatedAt < ActiveRecord::Migration<%= migration_version %>
|
4
|
+
disable_ddl_transaction!
|
5
|
+
|
6
|
+
def change
|
7
|
+
reversible do |dir|
|
8
|
+
dir.up do
|
9
|
+
# Ensure this incremental update migration is idempotent
|
10
|
+
# with monolithic install migration.
|
11
|
+
return if connection.index_exists? :good_jobs, [:concurrency_key, :created_at]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
add_index :good_jobs, [:concurrency_key, :created_at], algorithm: :concurrently
|
16
|
+
end
|
17
|
+
end
|
data/lib/good_job/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: good_job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.9.
|
4
|
+
version: 4.9.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Sheldon
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-03-09 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: activejob
|
@@ -348,6 +348,7 @@ files:
|
|
348
348
|
- lib/generators/good_job/templates/install/migrations/create_good_jobs.rb.erb
|
349
349
|
- lib/generators/good_job/templates/update/migrations/01_create_good_jobs.rb.erb
|
350
350
|
- lib/generators/good_job/templates/update/migrations/02_add_jobs_finished_at_to_good_job_batches.rb.erb
|
351
|
+
- lib/generators/good_job/templates/update/migrations/03_add_index_good_jobs_concurrency_key_created_at.rb.erb
|
351
352
|
- lib/generators/good_job/update_generator.rb
|
352
353
|
- lib/good_job.rb
|
353
354
|
- lib/good_job/active_job_extensions/batches.rb
|