delayed_job_active_record 0.4.3 → 0.4.4

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.
@@ -15,5 +15,5 @@ Gem::Specification.new do |spec|
15
15
  spec.require_paths = ['lib']
16
16
  spec.summary = 'ActiveRecord backend for DelayedJob'
17
17
  spec.test_files = Dir.glob("spec/**/*")
18
- spec.version = '0.4.3'
18
+ spec.version = '0.4.4'
19
19
  end
@@ -37,50 +37,43 @@ module Delayed
37
37
 
38
38
  # When a worker is exiting, make sure we don't have any locked jobs.
39
39
  def self.clear_locks!(worker_name)
40
- update_all("locked_by = null, locked_at = null", ["locked_by = ?", worker_name])
40
+ where(:locked_by => worker_name).update_all(:locked_by => nil, :locked_at => nil)
41
41
  end
42
42
 
43
43
  def self.reserve(worker, max_run_time = Worker.max_run_time)
44
44
  # scope to filter to records that are "ready to run"
45
- readyScope = self.ready_to_run(worker.name, max_run_time)
45
+ ready_scope = self.ready_to_run(worker.name, max_run_time)
46
46
 
47
47
  # scope to filter to the single next eligible job
48
- nextScope = readyScope.scoped
49
- nextScope = nextScope.scoped(:conditions => ['priority >= ?', Worker.min_priority]) if Worker.min_priority
50
- nextScope = nextScope.scoped(:conditions => ['priority <= ?', Worker.max_priority]) if Worker.max_priority
51
- nextScope = nextScope.scoped(:conditions => ["queue IN (?)", Worker.queues]) if Worker.queues.any?
52
- nextScope = nextScope.scoped.by_priority.limit(1)
48
+ ready_scope = ready_scope.where('priority >= ?', Worker.min_priority) if Worker.min_priority
49
+ ready_scope = ready_scope.where('priority <= ?', Worker.max_priority) if Worker.max_priority
50
+ ready_scope = ready_scope.where(:queue => Worker.queues) if Worker.queues.any?
51
+ ready_scope = ready_scope.by_priority
53
52
 
54
53
  now = self.db_time_now
55
- job = nextScope.first
56
- return unless job
57
- job.with_lock do
58
- job.locked_at = now
59
- job.locked_by = worker.name
60
- job.save!
61
- end
62
- job
63
- end
64
54
 
65
- # Lock this job for this worker.
66
- # Returns true if we have the lock, false otherwise.
67
- def lock_exclusively!(max_run_time, worker)
68
- now = self.class.db_time_now
69
- affected_rows = if locked_by != worker
70
- # We don't own this job so we will update the locked_by name and the locked_at
71
- self.class.update_all(["locked_at = ?, locked_by = ?", now, worker], ["id = ? and (locked_at is null or locked_at < ?) and (run_at <= ?)", id, (now - max_run_time.to_i), now])
72
- else
73
- # We already own this job, this may happen if the job queue crashes.
74
- # Simply resume and update the locked_at
75
- self.class.update_all(["locked_at = ?", now], ["id = ? and locked_by = ?", id, worker])
76
- end
77
- if affected_rows == 1
78
- self.locked_at = now
79
- self.locked_by = worker
80
- self.changed_attributes.clear
81
- return true
55
+ # Optimizations for faster lookups on some common databases
56
+ case self.connection.adapter_name
57
+ when "PostgreSQL"
58
+ # Custom SQL required for PostgreSQL because postgres does not support UPDATE...LIMIT
59
+ # This locks the single record 'FOR UPDATE' in the subquery (http://www.postgresql.org/docs/9.0/static/sql-select.html#SQL-FOR-UPDATE-SHARE)
60
+ # Note: active_record would attempt to generate UPDATE...LIMIT like sql for postgres if we use a .limit() filter, but it would not use
61
+ # 'FOR UPDATE' and we would have many locking conflicts
62
+ quoted_table_name = self.connection.quote_table_name(self.table_name)
63
+ subquery_sql = ready_scope.limit(1).lock(true).select('id').to_sql
64
+ reserved = self.find_by_sql(["UPDATE #{quoted_table_name} SET locked_at = ?, locked_by = ? WHERE id IN (#{subquery_sql}) RETURNING *", now, worker.name])
65
+ reserved[0]
66
+ when "MySQL", "Mysql2"
67
+ # This works on MySQL and possibly some other DBs that support UPDATE...LIMIT. It uses separate queries to lock and return the job
68
+ count = ready_scope.limit(1).update_all(:locked_at => now, :locked_by => worker.name)
69
+ return nil if count == 0
70
+ self.where(:locked_at => now, :locked_by => worker.name).first
82
71
  else
83
- return false
72
+ # This is our old fashion, tried and true, but slower lookup
73
+ ready_scope.limit(worker.read_ahead).detect do |job|
74
+ count = ready_scope.where(:id => job.id).update_all(:locked_at => now, :locked_by => worker.name)
75
+ count == 1 && job.reload
76
+ end
84
77
  end
85
78
  end
86
79
 
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: 0.4.3
4
+ version: 0.4.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2013-03-02 00:00:00.000000000 Z
14
+ date: 2013-04-02 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activerecord
@@ -91,7 +91,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
91
  version: '0'
92
92
  segments:
93
93
  - 0
94
- hash: -4151912302057659194
94
+ hash: 1565525879185101901
95
95
  required_rubygems_version: !ruby/object:Gem::Requirement
96
96
  none: false
97
97
  requirements:
@@ -100,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
100
  version: '0'
101
101
  segments:
102
102
  - 0
103
- hash: -4151912302057659194
103
+ hash: 1565525879185101901
104
104
  requirements: []
105
105
  rubyforge_project:
106
106
  rubygems_version: 1.8.25