delayed_job_active_record 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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