delayed_job_active_record 4.1.2 → 4.1.7
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 +5 -5
- data/README.md +2 -4
- data/delayed_job_active_record.gemspec +6 -3
- data/lib/delayed/backend/active_record.rb +76 -47
- data/lib/delayed_job_active_record.rb +2 -0
- data/lib/generators/delayed_job/active_record_generator.rb +3 -3
- data/lib/generators/delayed_job/next_migration_version.rb +2 -0
- data/lib/generators/delayed_job/templates/migration.rb +1 -1
- data/lib/generators/delayed_job/upgrade_generator.rb +7 -1
- metadata +7 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 4b17b594310d702d4a5dddca0001c067751c5c70595405ab74cf5091951e8dbf
|
|
4
|
+
data.tar.gz: 2ccf2889e6d629cd46850873c8b1038eba50554ba7b76d1151974b750e70f3c1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d0c30a1d2e4b220a1a12e61cd8f6745e13093c275c8f323c565cf919e92d65c8b9fa6ba35ca06532f5db3316e2128012c53076099b6940de71d351d8b2c0f6b8
|
|
7
|
+
data.tar.gz: e6c1f74236b4c93a981bafda8b311d71db3edc25e90856d8bb9d72e8c9fe61df7642c23e72f30eae40fc99eecefc2a5e3e1a11393d9c66e0114ab926ecdace4b
|
data/README.md
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
**If you're viewing this at https://github.com/collectiveidea/delayed_job_active_record,
|
|
2
2
|
you're reading the documentation for the master branch.
|
|
3
3
|
[View documentation for the latest release
|
|
4
|
-
(4.1.
|
|
4
|
+
(4.1.7).](https://github.com/collectiveidea/delayed_job_active_record/tree/v4.1.7)**
|
|
5
5
|
|
|
6
6
|
# DelayedJob ActiveRecord Backend
|
|
7
7
|
|
|
8
8
|
[](https://rubygems.org/gems/delayed_job_active_record)
|
|
9
|
-
|
|
10
|
-
[](https://gemnasium.com/collectiveidea/delayed_job_active_record)
|
|
11
|
-
[](https://codeclimate.com/github/collectiveidea/delayed_job_active_record)
|
|
9
|
+

|
|
12
10
|
[](https://coveralls.io/r/collectiveidea/delayed_job_active_record)
|
|
13
11
|
|
|
14
12
|
## Installation
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
Gem::Specification.new do |spec|
|
|
2
|
-
spec.add_dependency "activerecord", [">= 3.0", "<
|
|
4
|
+
spec.add_dependency "activerecord", [">= 3.0", "< 8.0"]
|
|
3
5
|
spec.add_dependency "delayed_job", [">= 3.0", "< 5"]
|
|
4
6
|
spec.authors = ["Brian Ryckbost", "Matt Griffin", "Erik Michaels-Ober"]
|
|
5
7
|
spec.description = "ActiveRecord backend for Delayed::Job, originally authored by Tobias Lütke"
|
|
6
8
|
spec.email = ["bryckbost@gmail.com", "matt@griffinonline.org", "sferik@gmail.com"]
|
|
7
|
-
spec.files = %w
|
|
9
|
+
spec.files = %w[CONTRIBUTING.md LICENSE.md README.md delayed_job_active_record.gemspec] + Dir["lib/**/*.rb"]
|
|
8
10
|
spec.homepage = "http://github.com/collectiveidea/delayed_job_active_record"
|
|
9
11
|
spec.licenses = ["MIT"]
|
|
12
|
+
spec.metadata = { "rubygems_mfa_required" => "true" }
|
|
10
13
|
spec.name = "delayed_job_active_record"
|
|
11
14
|
spec.require_paths = ["lib"]
|
|
12
15
|
spec.summary = "ActiveRecord backend for DelayedJob"
|
|
13
|
-
spec.version = "4.1.
|
|
16
|
+
spec.version = "4.1.7"
|
|
14
17
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "active_record/version"
|
|
2
4
|
module Delayed
|
|
3
5
|
module Backend
|
|
@@ -10,7 +12,10 @@ module Delayed
|
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
def reserve_sql_strategy=(val)
|
|
13
|
-
|
|
15
|
+
if !(val == :optimized_sql || val == :default_sql)
|
|
16
|
+
raise ArgumentError, "allowed values are :optimized_sql or :default_sql"
|
|
17
|
+
end
|
|
18
|
+
|
|
14
19
|
@reserve_sql_strategy = val
|
|
15
20
|
end
|
|
16
21
|
end
|
|
@@ -34,6 +39,9 @@ module Delayed
|
|
|
34
39
|
end
|
|
35
40
|
|
|
36
41
|
scope :by_priority, lambda { order("priority ASC, run_at ASC") }
|
|
42
|
+
scope :min_priority, lambda { where("priority >= ?", Worker.min_priority) if Worker.min_priority }
|
|
43
|
+
scope :max_priority, lambda { where("priority <= ?", Worker.max_priority) if Worker.max_priority }
|
|
44
|
+
scope :for_queues, lambda { |queues = Worker.queues| where(queue: queues) if Array(queues).any? }
|
|
37
45
|
|
|
38
46
|
before_save :set_default_run_at
|
|
39
47
|
|
|
@@ -45,7 +53,12 @@ module Delayed
|
|
|
45
53
|
set_delayed_job_table_name
|
|
46
54
|
|
|
47
55
|
def self.ready_to_run(worker_name, max_run_time)
|
|
48
|
-
where(
|
|
56
|
+
where(
|
|
57
|
+
"((run_at <= ? AND (locked_at IS NULL OR locked_at < ?)) OR locked_by = ?) AND failed_at IS NULL",
|
|
58
|
+
db_time_now,
|
|
59
|
+
db_time_now - max_run_time,
|
|
60
|
+
worker_name
|
|
61
|
+
)
|
|
49
62
|
end
|
|
50
63
|
|
|
51
64
|
def self.before_fork
|
|
@@ -61,15 +74,13 @@ module Delayed
|
|
|
61
74
|
where(locked_by: worker_name).update_all(locked_by: nil, locked_at: nil)
|
|
62
75
|
end
|
|
63
76
|
|
|
64
|
-
def self.reserve(worker, max_run_time = Worker.max_run_time)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
ready_scope = ready_scope.where(queue: Worker.queues) if Worker.queues.any?
|
|
72
|
-
ready_scope = ready_scope.by_priority
|
|
77
|
+
def self.reserve(worker, max_run_time = Worker.max_run_time)
|
|
78
|
+
ready_scope =
|
|
79
|
+
ready_to_run(worker.name, max_run_time)
|
|
80
|
+
.min_priority
|
|
81
|
+
.max_priority
|
|
82
|
+
.for_queues
|
|
83
|
+
.by_priority
|
|
73
84
|
|
|
74
85
|
reserve_with_scope(ready_scope, worker, db_time_now)
|
|
75
86
|
end
|
|
@@ -88,41 +99,12 @@ module Delayed
|
|
|
88
99
|
|
|
89
100
|
def self.reserve_with_scope_using_optimized_sql(ready_scope, worker, now)
|
|
90
101
|
case connection.adapter_name
|
|
91
|
-
when "PostgreSQL"
|
|
92
|
-
|
|
93
|
-
# This locks the single record 'FOR UPDATE' in the subquery
|
|
94
|
-
# http://www.postgresql.org/docs/9.0/static/sql-select.html#SQL-FOR-UPDATE-SHARE
|
|
95
|
-
# Note: active_record would attempt to generate UPDATE...LIMIT like
|
|
96
|
-
# SQL for Postgres if we use a .limit() filter, but it would not
|
|
97
|
-
# use 'FOR UPDATE' and we would have many locking conflicts
|
|
98
|
-
quoted_table_name = connection.quote_table_name(table_name)
|
|
99
|
-
subquery_sql = ready_scope.limit(1).lock(true).select("id").to_sql
|
|
100
|
-
reserved = find_by_sql(["UPDATE #{quoted_table_name} SET locked_at = ?, locked_by = ? WHERE id IN (#{subquery_sql}) RETURNING *", now, worker.name])
|
|
101
|
-
reserved[0]
|
|
102
|
+
when "PostgreSQL", "PostGIS"
|
|
103
|
+
reserve_with_scope_using_optimized_postgres(ready_scope, worker, now)
|
|
102
104
|
when "MySQL", "Mysql2"
|
|
103
|
-
|
|
104
|
-
# MySQL 5.6.4 onwards millisecond precision exists, but the
|
|
105
|
-
# datetime object created doesn't have precision, so discarded
|
|
106
|
-
# while updating. But during the where clause, for mysql(>=5.6.4),
|
|
107
|
-
# it queries with precision as well. So removing the precision
|
|
108
|
-
now = now.change(usec: 0)
|
|
109
|
-
# This works on MySQL and possibly some other DBs that support
|
|
110
|
-
# UPDATE...LIMIT. It uses separate queries to lock and return the job
|
|
111
|
-
count = ready_scope.limit(1).update_all(locked_at: now, locked_by: worker.name)
|
|
112
|
-
return nil if count == 0
|
|
113
|
-
where(locked_at: now, locked_by: worker.name, failed_at: nil).first
|
|
105
|
+
reserve_with_scope_using_optimized_mysql(ready_scope, worker, now)
|
|
114
106
|
when "MSSQL", "Teradata"
|
|
115
|
-
|
|
116
|
-
# is called directly
|
|
117
|
-
subsubquery_sql = ready_scope.limit(1).to_sql
|
|
118
|
-
# select("id") doesn't generate a subquery, so force a subquery
|
|
119
|
-
subquery_sql = "SELECT id FROM (#{subsubquery_sql}) AS x"
|
|
120
|
-
quoted_table_name = connection.quote_table_name(table_name)
|
|
121
|
-
sql = ["UPDATE #{quoted_table_name} SET locked_at = ?, locked_by = ? WHERE id IN (#{subquery_sql})", now, worker.name]
|
|
122
|
-
count = connection.execute(sanitize_sql(sql))
|
|
123
|
-
return nil if count == 0
|
|
124
|
-
# MSSQL JDBC doesn't support OUTPUT INSERTED.* for returning a result set, so query locked row
|
|
125
|
-
where(locked_at: now, locked_by: worker.name, failed_at: nil).first
|
|
107
|
+
reserve_with_scope_using_optimized_mssql(ready_scope, worker, now)
|
|
126
108
|
# Fallback for unknown / other DBMS
|
|
127
109
|
else
|
|
128
110
|
reserve_with_scope_using_default_sql(ready_scope, worker, now)
|
|
@@ -130,13 +112,60 @@ module Delayed
|
|
|
130
112
|
end
|
|
131
113
|
|
|
132
114
|
def self.reserve_with_scope_using_default_sql(ready_scope, worker, now)
|
|
133
|
-
# This is our old fashion, tried and true, but slower lookup
|
|
134
|
-
|
|
115
|
+
# This is our old fashion, tried and true, but possibly slower lookup
|
|
116
|
+
# Instead of reading the entire job record for our detect loop, we select only the id,
|
|
117
|
+
# and only read the full job record after we've successfully locked the job.
|
|
118
|
+
# This can have a noticable impact on large read_ahead configurations and large payload jobs.
|
|
119
|
+
ready_scope.limit(worker.read_ahead).select(:id).detect do |job|
|
|
135
120
|
count = ready_scope.where(id: job.id).update_all(locked_at: now, locked_by: worker.name)
|
|
136
121
|
count == 1 && job.reload
|
|
137
122
|
end
|
|
138
123
|
end
|
|
139
124
|
|
|
125
|
+
def self.reserve_with_scope_using_optimized_postgres(ready_scope, worker, now)
|
|
126
|
+
# Custom SQL required for PostgreSQL because postgres does not support UPDATE...LIMIT
|
|
127
|
+
# This locks the single record 'FOR UPDATE' in the subquery
|
|
128
|
+
# http://www.postgresql.org/docs/9.0/static/sql-select.html#SQL-FOR-UPDATE-SHARE
|
|
129
|
+
# Note: active_record would attempt to generate UPDATE...LIMIT like
|
|
130
|
+
# SQL for Postgres if we use a .limit() filter, but it would not
|
|
131
|
+
# use 'FOR UPDATE' and we would have many locking conflicts
|
|
132
|
+
quoted_name = connection.quote_table_name(table_name)
|
|
133
|
+
subquery = ready_scope.limit(1).lock(true).select("id").to_sql
|
|
134
|
+
sql = "UPDATE #{quoted_name} SET locked_at = ?, locked_by = ? WHERE id IN (#{subquery}) RETURNING *"
|
|
135
|
+
reserved = find_by_sql([sql, now, worker.name])
|
|
136
|
+
reserved[0]
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def self.reserve_with_scope_using_optimized_mysql(ready_scope, worker, now)
|
|
140
|
+
# Removing the millisecond precision from now(time object)
|
|
141
|
+
# MySQL 5.6.4 onwards millisecond precision exists, but the
|
|
142
|
+
# datetime object created doesn't have precision, so discarded
|
|
143
|
+
# while updating. But during the where clause, for mysql(>=5.6.4),
|
|
144
|
+
# it queries with precision as well. So removing the precision
|
|
145
|
+
now = now.change(usec: 0)
|
|
146
|
+
# This works on MySQL and possibly some other DBs that support
|
|
147
|
+
# UPDATE...LIMIT. It uses separate queries to lock and return the job
|
|
148
|
+
count = ready_scope.limit(1).update_all(locked_at: now, locked_by: worker.name)
|
|
149
|
+
return nil if count == 0
|
|
150
|
+
|
|
151
|
+
where(locked_at: now, locked_by: worker.name, failed_at: nil).first
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def self.reserve_with_scope_using_optimized_mssql(ready_scope, worker, now)
|
|
155
|
+
# The MSSQL driver doesn't generate a limit clause when update_all
|
|
156
|
+
# is called directly
|
|
157
|
+
subsubquery_sql = ready_scope.limit(1).to_sql
|
|
158
|
+
# select("id") doesn't generate a subquery, so force a subquery
|
|
159
|
+
subquery_sql = "SELECT id FROM (#{subsubquery_sql}) AS x"
|
|
160
|
+
quoted_table_name = connection.quote_table_name(table_name)
|
|
161
|
+
sql = "UPDATE #{quoted_table_name} SET locked_at = ?, locked_by = ? WHERE id IN (#{subquery_sql})"
|
|
162
|
+
count = connection.execute(sanitize_sql([sql, now, worker.name]))
|
|
163
|
+
return nil if count == 0
|
|
164
|
+
|
|
165
|
+
# MSSQL JDBC doesn't support OUTPUT INSERTED.* for returning a result set, so query locked row
|
|
166
|
+
where(locked_at: now, locked_by: worker.name, failed_at: nil).first
|
|
167
|
+
end
|
|
168
|
+
|
|
140
169
|
# Get the current time (GMT or local depending on DB)
|
|
141
170
|
# Note: This does not ping the DB to get the time, so all your clients
|
|
142
171
|
# must have syncronized clocks.
|
|
@@ -146,7 +175,7 @@ module Delayed
|
|
|
146
175
|
elsif ::ActiveRecord::Base.default_timezone == :utc
|
|
147
176
|
Time.now.utc
|
|
148
177
|
else
|
|
149
|
-
Time.now
|
|
178
|
+
Time.now # rubocop:disable Rails/TimeZone
|
|
150
179
|
end
|
|
151
180
|
end
|
|
152
181
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "generators/delayed_job/delayed_job_generator"
|
|
2
4
|
require "generators/delayed_job/next_migration_version"
|
|
3
5
|
require "rails/generators/migration"
|
|
@@ -22,9 +24,7 @@ module DelayedJob
|
|
|
22
24
|
private
|
|
23
25
|
|
|
24
26
|
def migration_version
|
|
25
|
-
if ActiveRecord::VERSION::MAJOR >= 5
|
|
26
|
-
"[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
|
|
27
|
-
end
|
|
27
|
+
"[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]" if ActiveRecord::VERSION::MAJOR >= 5
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
class CreateDelayedJobs < ActiveRecord::Migration<%= migration_version %>
|
|
2
2
|
def self.up
|
|
3
|
-
create_table :delayed_jobs
|
|
3
|
+
create_table :delayed_jobs do |table|
|
|
4
4
|
table.integer :priority, default: 0, null: false # Allows some jobs to jump to the front of the queue
|
|
5
5
|
table.integer :attempts, default: 0, null: false # Provides for retries, but still fail eventually.
|
|
6
6
|
table.text :handler, null: false # YAML-encoded string of the object that will do work
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "generators/delayed_job/delayed_job_generator"
|
|
2
4
|
require "generators/delayed_job/next_migration_version"
|
|
3
5
|
require "rails/generators/migration"
|
|
@@ -7,7 +9,11 @@ require "rails/generators/active_record"
|
|
|
7
9
|
module DelayedJob
|
|
8
10
|
class UpgradeGenerator < ActiveRecordGenerator
|
|
9
11
|
def create_migration_file
|
|
10
|
-
migration_template
|
|
12
|
+
migration_template(
|
|
13
|
+
"upgrade_migration.rb",
|
|
14
|
+
"db/migrate/add_queue_to_delayed_jobs.rb",
|
|
15
|
+
migration_version: migration_version
|
|
16
|
+
)
|
|
11
17
|
end
|
|
12
18
|
end
|
|
13
19
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: delayed_job_active_record
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.1.
|
|
4
|
+
version: 4.1.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brian Ryckbost
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date:
|
|
13
|
+
date: 2022-01-18 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: activerecord
|
|
@@ -21,7 +21,7 @@ dependencies:
|
|
|
21
21
|
version: '3.0'
|
|
22
22
|
- - "<"
|
|
23
23
|
- !ruby/object:Gem::Version
|
|
24
|
-
version: '
|
|
24
|
+
version: '8.0'
|
|
25
25
|
type: :runtime
|
|
26
26
|
prerelease: false
|
|
27
27
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -31,7 +31,7 @@ dependencies:
|
|
|
31
31
|
version: '3.0'
|
|
32
32
|
- - "<"
|
|
33
33
|
- !ruby/object:Gem::Version
|
|
34
|
-
version: '
|
|
34
|
+
version: '8.0'
|
|
35
35
|
- !ruby/object:Gem::Dependency
|
|
36
36
|
name: delayed_job
|
|
37
37
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -76,7 +76,8 @@ files:
|
|
|
76
76
|
homepage: http://github.com/collectiveidea/delayed_job_active_record
|
|
77
77
|
licenses:
|
|
78
78
|
- MIT
|
|
79
|
-
metadata:
|
|
79
|
+
metadata:
|
|
80
|
+
rubygems_mfa_required: 'true'
|
|
80
81
|
post_install_message:
|
|
81
82
|
rdoc_options: []
|
|
82
83
|
require_paths:
|
|
@@ -92,8 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
92
93
|
- !ruby/object:Gem::Version
|
|
93
94
|
version: '0'
|
|
94
95
|
requirements: []
|
|
95
|
-
|
|
96
|
-
rubygems_version: 2.6.11
|
|
96
|
+
rubygems_version: 3.1.4
|
|
97
97
|
signing_key:
|
|
98
98
|
specification_version: 4
|
|
99
99
|
summary: ActiveRecord backend for DelayedJob
|