delayed_job_loner 0.0.1 → 0.0.2
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.
- data/.rspec +2 -0
- data/README.md +33 -2
- data/delayed_job_loner.gemspec +8 -0
- data/lib/delayed_job_loner/init.rb +5 -4
- data/lib/delayed_job_loner/version.rb +1 -1
- data/spec/delayed_job_loner_spec.rb +33 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/story.rb +45 -0
- metadata +107 -4
data/.rspec
ADDED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# DelayedJobLoner
|
2
2
|
|
3
|
-
|
3
|
+
Adds an option on handle_asynchronously or delay that specifies which attributes to check for uniqueness on. A new job will not be created if one already exists for that method and object.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -18,7 +18,38 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
|
21
|
+
Pass the option `:unique_on` to any method that you would provide `:priority` or `:run_at`. `:unique_on` should be an array of attributes that you want to check the uniqueness of the job against.
|
22
|
+
Here is an example:
|
23
|
+
```ruby
|
24
|
+
class Foo < ActiveRecord::Base
|
25
|
+
|
26
|
+
def do_all_the_things
|
27
|
+
# All the things!
|
28
|
+
end
|
29
|
+
handle_asynchronously :do_all_the_things, :unique_on => [:id]
|
30
|
+
|
31
|
+
def do_some_of_the_things
|
32
|
+
# Some of the things!
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
This allows you to do things like this:
|
39
|
+
```ruby
|
40
|
+
foo = Foo.first
|
41
|
+
foo.do_all_the_things
|
42
|
+
# Creates a new job
|
43
|
+
foo.do_all_the_things
|
44
|
+
# Doesn't create a new job because we already created one
|
45
|
+
|
46
|
+
foo.delay(:priority => 10).do_some_of_the_things
|
47
|
+
# Creates a new job
|
48
|
+
foo.delay(:priority => 10, :unique_on => [:id]).do_some_of_the_things
|
49
|
+
# Doesn't create a new job
|
50
|
+
foo.delay(:priority => 10).do_some_of_the_things
|
51
|
+
# Creates a new job because we didn't specify :unique_on
|
52
|
+
```
|
22
53
|
|
23
54
|
## Contributing
|
24
55
|
|
data/delayed_job_loner.gemspec
CHANGED
@@ -14,4 +14,12 @@ Gem::Specification.new do |gem|
|
|
14
14
|
gem.name = "delayed_job_loner"
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = DelayedJobLoner::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency 'delayed_job'
|
19
|
+
|
20
|
+
gem.add_development_dependency 'rspec'
|
21
|
+
gem.add_development_dependency 'activerecord'
|
22
|
+
gem.add_development_dependency 'sqlite3-ruby'
|
23
|
+
gem.add_development_dependency 'sqlite3_ar_regexp'
|
24
|
+
gem.add_development_dependency 'delayed_job_active_record'
|
17
25
|
end
|
@@ -3,16 +3,17 @@ module Delayed
|
|
3
3
|
module ActiveRecord
|
4
4
|
class Job < ::ActiveRecord::Base
|
5
5
|
attr_accessor :unique_on
|
6
|
+
attr_accessible :unique_on
|
6
7
|
|
7
|
-
|
8
|
+
validate :check_uniqueness
|
8
9
|
|
9
10
|
def check_uniqueness
|
10
11
|
if unique_on
|
11
|
-
scope = self.class.where("handler
|
12
|
+
scope = self.class.where("handler REGEXP '\\nmethod_name: :#{payload_object.method_name}\\n'").where(:locked_by => nil)
|
12
13
|
unique_on.each do |attribute_name|
|
13
|
-
scope = scope.where("handler
|
14
|
+
scope = scope.where("handler REGEXP ' +#{attribute_name}: #{payload_object.send(attribute_name)}\\n'")
|
14
15
|
end
|
15
|
-
scope.first.nil?
|
16
|
+
self.errors.add(:base, "Job already exists") unless scope.first.nil?
|
16
17
|
else
|
17
18
|
true
|
18
19
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "story"
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe DelayedJobLoner do
|
5
|
+
|
6
|
+
it "should create a job if :unique_on is not specified" do
|
7
|
+
story = Story.create(:text => "foo")
|
8
|
+
story.reload
|
9
|
+
story.delay.tell.persisted?.should eql true
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should create a job if :unique_on is specified and a similar job does not exist" do
|
13
|
+
story = Story.create(:text => "foo")
|
14
|
+
story2 = Story.create(:text => "foo")
|
15
|
+
story.reload
|
16
|
+
story2.reload
|
17
|
+
|
18
|
+
story.delay.tell.persisted?.should eql true
|
19
|
+
story2.delay(:unique_on => [:id]).tell.persisted?.should eql true
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should not create a job if :unique_on is specified and a similar job exists" do
|
23
|
+
story = Story.create(:text => "foo")
|
24
|
+
story.reload
|
25
|
+
|
26
|
+
story.whatever.persisted?.should eql true
|
27
|
+
story.whatever.persisted?.should eql false
|
28
|
+
|
29
|
+
story.delay(:unique_on => [:id]).tell.persisted?.should eql true
|
30
|
+
story.delay(:unique_on => [:id]).tell.persisted?.should eql false
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
9
|
+
config.run_all_when_everything_filtered = true
|
10
|
+
config.filter_run :focus
|
11
|
+
end
|
data/spec/story.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'delayed_job'
|
3
|
+
require 'delayed_job_active_record'
|
4
|
+
require 'delayed_job_loner'
|
5
|
+
require 'sqlite3_ar_regexp'
|
6
|
+
|
7
|
+
ActiveRecord::Base.logger = Logger.new('/tmp/dj.log')
|
8
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => '/tmp/jobs.sqlite')
|
9
|
+
ActiveRecord::Migration.verbose = false
|
10
|
+
ActiveRecord::Base.default_timezone = :utc if Time.zone.nil?
|
11
|
+
|
12
|
+
ActiveRecord::Schema.define do
|
13
|
+
|
14
|
+
create_table :delayed_jobs, :force => true do |table|
|
15
|
+
table.integer :priority, :default => 0
|
16
|
+
table.integer :attempts, :default => 0
|
17
|
+
table.text :handler
|
18
|
+
table.string :last_error
|
19
|
+
table.datetime :run_at
|
20
|
+
table.datetime :locked_at
|
21
|
+
table.string :locked_by
|
22
|
+
table.datetime :failed_at
|
23
|
+
table.timestamps
|
24
|
+
end
|
25
|
+
|
26
|
+
create_table :stories, :force => true do |table|
|
27
|
+
table.string :id, :text
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
# Purely useful for test cases...
|
33
|
+
class Story < ActiveRecord::Base
|
34
|
+
attr_accessor :id
|
35
|
+
|
36
|
+
def tell
|
37
|
+
text
|
38
|
+
end
|
39
|
+
|
40
|
+
def whatever
|
41
|
+
tell
|
42
|
+
end
|
43
|
+
handle_asynchronously :whatever, :unique_on => [:id], :priority => 10
|
44
|
+
|
45
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: delayed_job_loner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,104 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-08-
|
13
|
-
dependencies:
|
12
|
+
date: 2012-08-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: delayed_job
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: activerecord
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: sqlite3-ruby
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: sqlite3_ar_regexp
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: delayed_job_active_record
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
14
110
|
description: Gem that adds the ability to prevent duplicate delayed jobs from being
|
15
111
|
created.
|
16
112
|
email:
|
@@ -20,6 +116,7 @@ extensions: []
|
|
20
116
|
extra_rdoc_files: []
|
21
117
|
files:
|
22
118
|
- .gitignore
|
119
|
+
- .rspec
|
23
120
|
- Gemfile
|
24
121
|
- LICENSE
|
25
122
|
- README.md
|
@@ -28,6 +125,9 @@ files:
|
|
28
125
|
- lib/delayed_job_loner.rb
|
29
126
|
- lib/delayed_job_loner/init.rb
|
30
127
|
- lib/delayed_job_loner/version.rb
|
128
|
+
- spec/delayed_job_loner_spec.rb
|
129
|
+
- spec/spec_helper.rb
|
130
|
+
- spec/story.rb
|
31
131
|
homepage: https://github.com/tstmedia/delayed_job_loner
|
32
132
|
licenses: []
|
33
133
|
post_install_message:
|
@@ -54,4 +154,7 @@ specification_version: 3
|
|
54
154
|
summary: Adds an option on handle_asynchronously or delay that specifies which attributes
|
55
155
|
to check for uniqueness on. A new job will not be created if one already exists
|
56
156
|
for that method and object.
|
57
|
-
test_files:
|
157
|
+
test_files:
|
158
|
+
- spec/delayed_job_loner_spec.rb
|
159
|
+
- spec/spec_helper.rb
|
160
|
+
- spec/story.rb
|