delayed_job_active_record 4.1.1 → 4.1.5

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: 3fd97d1444b2e5cbf2bfa22b304cde221619558d
4
- data.tar.gz: 000b0e8eedbd1c0d2f470288d03f3349bf72f2d8
2
+ SHA256:
3
+ metadata.gz: 1799d6d0f6301b5285da09c332bfe6abeb6cfb60b410a29e93f94a99aa0313b7
4
+ data.tar.gz: a1b0adfed07a2a7f47603390156688e193aed7bcc187184c9812b72e182fb859
5
5
  SHA512:
6
- metadata.gz: 689515b8aa68f2395b5f5d3ab31f0b2fb8098bb8cdc8f3f93eb1cbcd93db84d6cb78db67e43e1b6fe93f999bd3a9d61aecf3138ec17a0bac6439c9600a387ec6
7
- data.tar.gz: 2488595100525ad2b22c1112dd6a90e37507e47342e6fdb936d5ba465662dac49e0092b91d1a03bf6feb7facfaf1624161456ae682d1733943231b6c8848c14f
6
+ metadata.gz: c17b88c4d64f8698405c1cf9918b887baecbd2366d42a71d4d02879227d339aba4de0ba3419fc3a4cc0272b193769709efb86fd95f251a08afa4e9c00d07ac58
7
+ data.tar.gz: 9d8bc65f7e959d71264c8d46d2cff8c2409a975755be9c5a9f0387d033bf1054d76c20e56a0dd685f7556b9cde282dd7c76818f733c9ad9e28fc9e7cbaa67da1
data/README.md CHANGED
@@ -1,15 +1,13 @@
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.0).](https://github.com/collectiveidea/delayed_job_active_record/tree/v4.1.0)**
4
+ (4.1.5).](https://github.com/collectiveidea/delayed_job_active_record/tree/v4.1.5)**
5
5
 
6
6
  # DelayedJob ActiveRecord Backend
7
7
 
8
- [![Gem Version](https://badge.fury.io/rb/delayed_job_active_record.png)](https://rubygems.org/gems/delayed_job_active_record)
9
- [![Build Status](https://travis-ci.org/collectiveidea/delayed_job_active_record.png)](https://travis-ci.org/collectiveidea/delayed_job_active_record)
10
- [![Dependency Status](https://gemnasium.com/collectiveidea/delayed_job_active_record.png)](https://gemnasium.com/collectiveidea/delayed_job_active_record)
11
- [![Code Climate](https://codeclimate.com/github/collectiveidea/delayed_job_active_record.png)](https://codeclimate.com/github/collectiveidea/delayed_job_active_record)
12
- [![Coverage Status](https://coveralls.io/repos/collectiveidea/delayed_job_active_record/badge.png?branch=master)](https://coveralls.io/r/collectiveidea/delayed_job_active_record)
8
+ [![Gem Version](https://img.shields.io/gem/v/delayed_job_active_record.svg)](https://rubygems.org/gems/delayed_job_active_record)
9
+ ![CI](https://github.com/collectiveidea/delayed_job_active_record/workflows/CI/badge.svg)
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
15
13
 
@@ -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.1"]
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.1"
15
+ spec.version = "4.1.5"
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
 
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Delayed
4
+ module Backend
5
+ module ActiveRecord
6
+ class Railtie < ::Rails::Railtie
7
+ config.after_initialize do
8
+ require "delayed/backend/active_record"
9
+ Delayed::Worker.backend = :active_record
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,5 +1,12 @@
1
- require "active_record"
1
+ # frozen_string_literal: true
2
+
2
3
  require "delayed_job"
3
- require "delayed/backend/active_record"
4
4
 
5
- Delayed::Worker.backend = :active_record
5
+ if defined?(Rails::Railtie)
6
+ require "delayed/backend/active_record/railtie"
7
+ else
8
+ require "active_record"
9
+ require "delayed/backend/active_record"
10
+
11
+ Delayed::Worker.backend = :active_record
12
+ end
@@ -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"
@@ -12,11 +14,17 @@ module DelayedJob
12
14
  source_paths << File.join(File.dirname(__FILE__), "templates")
13
15
 
14
16
  def create_migration_file
15
- migration_template "migration.rb", "db/migrate/create_delayed_jobs.rb"
17
+ migration_template "migration.rb", "db/migrate/create_delayed_jobs.rb", migration_version: migration_version
16
18
  end
17
19
 
18
20
  def self.next_migration_number(dirname)
19
21
  ActiveRecord::Generators::Base.next_migration_number dirname
20
22
  end
23
+
24
+ private
25
+
26
+ def migration_version
27
+ "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]" if ActiveRecord::VERSION::MAJOR >= 5
28
+ end
21
29
  end
22
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
- class CreateDelayedJobs < ActiveRecord::Migration
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,4 +1,4 @@
1
- class AddQueueToDelayedJobs < ActiveRecord::Migration
1
+ class AddQueueToDelayedJobs < ActiveRecord::Migration<%= migration_version %>
2
2
  def self.up
3
3
  add_column :delayed_jobs, :queue, :string
4
4
  end
@@ -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"
@@ -5,18 +7,13 @@ require "rails/generators/active_record"
5
7
 
6
8
  # Extend the DelayedJobGenerator so that it creates an AR migration
7
9
  module DelayedJob
8
- class UpgradeGenerator < ::DelayedJobGenerator
9
- include Rails::Generators::Migration
10
- extend NextMigrationVersion
11
-
12
- source_paths << File.join(File.dirname(__FILE__), "templates")
13
-
10
+ class UpgradeGenerator < ActiveRecordGenerator
14
11
  def create_migration_file
15
- migration_template "upgrade_migration.rb", "db/migrate/add_queue_to_delayed_jobs.rb"
16
- end
17
-
18
- def self.next_migration_number(dirname)
19
- ActiveRecord::Generators::Base.next_migration_number dirname
12
+ migration_template(
13
+ "upgrade_migration.rb",
14
+ "db/migrate/add_queue_to_delayed_jobs.rb",
15
+ migration_version: migration_version
16
+ )
20
17
  end
21
18
  end
22
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.1
4
+ version: 4.1.5
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: 2016-05-16 00:00:00.000000000 Z
13
+ date: 2020-12-09 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.1'
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.1'
34
+ version: '6.2'
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: delayed_job
37
37
  requirement: !ruby/object:Gem::Requirement
@@ -67,6 +67,7 @@ files:
67
67
  - README.md
68
68
  - delayed_job_active_record.gemspec
69
69
  - lib/delayed/backend/active_record.rb
70
+ - lib/delayed/backend/active_record/railtie.rb
70
71
  - lib/delayed_job_active_record.rb
71
72
  - lib/generators/delayed_job/active_record_generator.rb
72
73
  - lib/generators/delayed_job/next_migration_version.rb
@@ -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.5.1
96
+ rubygems_version: 3.0.3
97
97
  signing_key:
98
98
  specification_version: 4
99
99
  summary: ActiveRecord backend for DelayedJob