delayed_job_active_record 4.1.2 → 4.1.6

Sign up to get free protection for your applications and to get access to all the features.
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: 3a381933e56413c64769a9ccd2eaf1c8fd632dcf82cf95c7986ebb10cdb2b3d3
4
+ data.tar.gz: e1fc2eec65dd2d698d5637bf977a8a6f15f535ad6cca12118e56b329a454b6aa
5
5
  SHA512:
6
- metadata.gz: 123564b7b3f54d4ee8cdd1673e5fb5471f564e1306a69c3fc07e4e6b4ea6608f448f493170840137604705731ba9e5f488c00ed6a1272fd9f263622e83db385e
7
- data.tar.gz: fa7fff077b2f611118b21abf9e106cf8b210c5ad1b9404dc9c6c8c678164f991486bd38f885e062cef233d4a082c03badca4bc333bec92f25d138215b0215184
6
+ metadata.gz: e1c57c495800a0146ffa3955c4982ead69b8707ada1336e7f0e348ec47e55b5bfe9802ce0093a2ec553b70d90afed1251c74f3e50a27be338a5e9b2a17f6e054
7
+ data.tar.gz: a8fbf28854f9a699c72f20ea209a0630d1289c09c4fa93b23888a7d942bd1739640eeeabb80a4d1cb36fbe0c2d3562a869943ab13218ce4a9a294d1cbeb019f1
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.6).](https://github.com/collectiveidea/delayed_job_active_record/tree/v4.1.6)**
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,16 @@
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", "< 6.2"]
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"]
10
12
  spec.name = "delayed_job_active_record"
11
13
  spec.require_paths = ["lib"]
12
14
  spec.summary = "ActiveRecord backend for DelayedJob"
13
- spec.version = "4.1.2"
15
+ spec.version = "4.1.6"
14
16
  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.6
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: 2021-03-26 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: '6.2'
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: '6.2'
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: delayed_job
37
37
  requirement: !ruby/object:Gem::Requirement
@@ -92,8 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
92
  - !ruby/object:Gem::Version
93
93
  version: '0'
94
94
  requirements: []
95
- rubyforge_project:
96
- rubygems_version: 2.6.11
95
+ rubygems_version: 3.0.3
97
96
  signing_key:
98
97
  specification_version: 4
99
98
  summary: ActiveRecord backend for DelayedJob