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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 587c2fcfd39aed7965f484c0e9ba9bc94dba926b
4
- data.tar.gz: d71c55d818a0e780d972bb35c0d665195e47467e
2
+ SHA256:
3
+ metadata.gz: 4b17b594310d702d4a5dddca0001c067751c5c70595405ab74cf5091951e8dbf
4
+ data.tar.gz: 2ccf2889e6d629cd46850873c8b1038eba50554ba7b76d1151974b750e70f3c1
5
5
  SHA512:
6
- metadata.gz: 123564b7b3f54d4ee8cdd1673e5fb5471f564e1306a69c3fc07e4e6b4ea6608f448f493170840137604705731ba9e5f488c00ed6a1272fd9f263622e83db385e
7
- data.tar.gz: fa7fff077b2f611118b21abf9e106cf8b210c5ad1b9404dc9c6c8c678164f991486bd38f885e062cef233d4a082c03badca4bc333bec92f25d138215b0215184
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.2).](https://github.com/collectiveidea/delayed_job_active_record/tree/v4.1.2)**
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
  [![Gem Version](https://img.shields.io/gem/v/delayed_job_active_record.svg)](https://rubygems.org/gems/delayed_job_active_record)
9
- [![Build Status](https://img.shields.io/travis/collectiveidea/delayed_job_active_record.svg)](https://travis-ci.org/collectiveidea/delayed_job_active_record)
10
- [![Dependency Status](https://img.shields.io/gemnasium/collectiveidea/delayed_job_active_record.svg)](https://gemnasium.com/collectiveidea/delayed_job_active_record)
11
- [![Code Climate](https://img.shields.io/codeclimate/github/collectiveidea/delayed_job_active_record.svg)](https://codeclimate.com/github/collectiveidea/delayed_job_active_record)
9
+ ![CI](https://github.com/collectiveidea/delayed_job_active_record/workflows/CI/badge.svg)
12
10
  [![Coverage Status](https://img.shields.io/coveralls/collectiveidea/delayed_job_active_record.svg)](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", "< 5.2"]
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(CONTRIBUTING.md LICENSE.md README.md delayed_job_active_record.gemspec) + Dir["lib/**/*.rb"]
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.2"
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
- raise ArgumentError, "allowed values are :optimized_sql or :default_sql" unless val == :optimized_sql || val == :default_sql
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("(run_at <= ? AND (locked_at IS NULL OR locked_at < ?) OR locked_by = ?) AND failed_at IS NULL", db_time_now, db_time_now - max_run_time, worker_name)
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) # rubocop:disable CyclomaticComplexity
65
- # scope to filter to records that are "ready to run"
66
- ready_scope = ready_to_run(worker.name, max_run_time)
67
-
68
- # scope to filter to the single next eligible job
69
- ready_scope = ready_scope.where("priority >= ?", Worker.min_priority) if Worker.min_priority
70
- ready_scope = ready_scope.where("priority <= ?", Worker.max_priority) if Worker.max_priority
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
- # Custom SQL required for PostgreSQL because postgres does not support UPDATE...LIMIT
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
- # Removing the millisecond precision from now(time object)
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
- # The MSSQL driver doesn't generate a limit clause when update_all
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
- ready_scope.limit(worker.read_ahead).detect do |job|
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 "active_record"
2
4
  require "delayed_job"
3
5
  require "delayed/backend/active_record"
@@ -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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DelayedJob
2
4
  module NextMigrationVersion
3
5
  # while methods have moved around this has been the implementation
@@ -1,6 +1,6 @@
1
1
  class CreateDelayedJobs < ActiveRecord::Migration<%= migration_version %>
2
2
  def self.up
3
- create_table :delayed_jobs, force: true do |table|
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 "upgrade_migration.rb", "db/migrate/add_queue_to_delayed_jobs.rb", migration_version: migration_version
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.2
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: 2017-05-27 00:00:00.000000000 Z
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: '5.2'
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: '5.2'
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
- rubyforge_project:
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