mongoid-locker 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Binary file
data/demo/showoff.css ADDED
@@ -0,0 +1,16 @@
1
+ #preso,
2
+ .slide {
3
+ position: absolute;
4
+ top: 0;
5
+ left: 0;
6
+ right: 0;
7
+ bottom: 0;
8
+ width: auto;
9
+ height: auto;
10
+ overflow: auto;
11
+ }
12
+
13
+ pre.sh_sourceCode {
14
+ font-size: 2.5em;
15
+ line-height: 1.2;
16
+ }
data/demo/showoff.md ADDED
@@ -0,0 +1,159 @@
1
+ !SLIDE
2
+
3
+ # Mongoid-Locker
4
+
5
+ [github.com/afeld/mongoid-locker](https://github.com/afeld/mongoid-locker)
6
+
7
+ ## Aidan Feldman, [Jux.com](https://jux.com)
8
+
9
+ !SLIDE
10
+
11
+ ![Instagram diagram](instagram.png)
12
+
13
+ !SLIDE
14
+
15
+ # Jux needed a queue.
16
+
17
+ * Distributed, but synchronized
18
+ * No add'l DB
19
+ * No add'l hassle (managing workers, etc.)
20
+
21
+ !SLIDE
22
+
23
+ * Thread
24
+ - \+ Distributed
25
+ - – Not synchronized
26
+ * Many workers
27
+ - \+ Distributed
28
+ - – Not synchronized
29
+ * One worker
30
+ - \+ Synchronized
31
+ - – Not distributed
32
+ - – Single POF
33
+
34
+ !SLIDE
35
+
36
+ @@@ ruby
37
+ require 'rubygems'
38
+ require 'mongoid-locker'
39
+ Mongoid.load!('config/mongoid.yml', :development)
40
+
41
+
42
+ class User
43
+ include Mongoid::Document
44
+ # include Mongoid::Locker
45
+
46
+ field :balance, type: Float
47
+ end
48
+
49
+ # cleanup
50
+ User.destroy_all
51
+
52
+ bob = User.create!(balance: 100.00)
53
+
54
+ !SLIDE
55
+
56
+ # Atomic Operations
57
+
58
+ @@@ ruby
59
+ class User
60
+ def purchase(amount)
61
+ if amount > self.balance
62
+ raise "Can't have negative balance!"
63
+ else
64
+ # deduct *atomically*
65
+ self.inc(:balance, -1 * amount)
66
+ # a.k.a.
67
+ # db.users.update({_id: ...}, {$inc: {balance: ...}})
68
+
69
+ puts "cha-ching!"
70
+ end
71
+ end
72
+ end
73
+
74
+ bob.purchase(5.10) #=> "cha-ching!"
75
+ bob.purchase(110.53) #=> "Can't have negative balance!"
76
+
77
+ !SLIDE
78
+
79
+ # All fine, right?
80
+
81
+ !SLIDE
82
+
83
+ @@@ ruby
84
+ class User
85
+ def purchase(amount)
86
+ if amount > self.balance
87
+ raise "Can't have negative balance!"
88
+ else
89
+ # artificial delay
90
+ print 'has enough money...waiting for ENTER > '
91
+ gets
92
+
93
+ self.inc(:balance, -1 * amount)
94
+ puts "cha-ching!"
95
+ end
96
+ end
97
+ end
98
+
99
+ !SLIDE
100
+
101
+ @@@ ruby
102
+ # shell 1
103
+ bob.purchase(10.00)
104
+
105
+ # shell 2
106
+ also_bob = User.first
107
+ also_bob.purchase(95.00)
108
+
109
+ !SLIDE
110
+
111
+ # oops.
112
+
113
+ !SLIDE
114
+
115
+ @@@ ruby
116
+ class User
117
+ # add doc-level locking
118
+ include Mongoid::Locker
119
+ timeout_lock_after 20
120
+
121
+ def purchase(amount)
122
+ # only one at a time
123
+ self.with_lock(wait: true) do
124
+ # after the `wait`, will have updated `balance`
125
+
126
+ if amount > self.balance
127
+ raise "Can't have negative balance!"
128
+ else
129
+ print 'has enough money...waiting for ENTER > '
130
+ gets
131
+
132
+ self.inc(:balance, -1 * amount)
133
+ puts "cha-ching!"
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ !SLIDE
140
+
141
+ # Summary
142
+
143
+ * Easy document-level locking
144
+ * Useful for queueing or pseudo-transactions
145
+ * No additional dependencies
146
+
147
+ !SLIDE
148
+
149
+ # Fin.
150
+
151
+ [afeld/mongoid-locker](https://github.com/afeld/mongoid-locker)
152
+
153
+ ----------------
154
+
155
+ ## Aidan Feldman, [Jux.com](https://jux.com)
156
+
157
+ [@aidanfeldman](https://twitter.com/aidanfeldman)
158
+
159
+ [afeld.me](http://afeld.me)
@@ -120,6 +120,8 @@ module Mongoid
120
120
  opts.dup
121
121
  opts.delete :wait
122
122
 
123
+ # reload to update with any new values
124
+ self.reload
123
125
  # retry lock grab
124
126
  self.lock opts
125
127
  else
@@ -2,7 +2,7 @@ module Mongoid
2
2
  module Locker
3
3
  # Normalizes queries between Mongoid 2 and 3.
4
4
  module Wrapper
5
- IS_OLD_MONGOID = Mongoid::VERSION.start_with? '2'
5
+ IS_OLD_MONGOID = Mongoid::VERSION.start_with? '2.'
6
6
 
7
7
  # Update the document for the provided Class matching the provided query with the provided setter.
8
8
  #
@@ -11,12 +11,14 @@ module Mongoid
11
11
  # @param [Hash] The Mongoid setter
12
12
  # @return [Boolean] true if the document was successfully updated, false otherwise
13
13
  def self.update klass, query, setter
14
- if IS_OLD_MONGOID
15
- error_obj = klass.collection.update(query, setter, :safe => true)
16
- error_obj['n'] == 1
17
- else
18
- !!klass.where(query).find_and_modify(setter, :new => false)
19
- end
14
+ error_obj =
15
+ if IS_OLD_MONGOID
16
+ klass.collection.update(query, setter, :safe => true)
17
+ else
18
+ klass.with(:safe => true).collection.find(query).update(setter)
19
+ end
20
+
21
+ error_obj['n'] == 1
20
22
  end
21
23
 
22
24
  # Determine whether the provided document is locked in the database or not.
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "mongoid-locker"
8
- s.version = "0.2.0"
8
+ s.version = "0.2.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Aidan Feldman"]
12
- s.date = "2012-08-27"
12
+ s.date = "2012-11-28"
13
13
  s.description = "Allows multiple processes to operate on individual documents in MongoDB while ensuring that only one can act at a time."
14
14
  s.email = "aidan.feldman@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -29,6 +29,12 @@ Gem::Specification.new do |s|
29
29
  "README.md",
30
30
  "Rakefile",
31
31
  "VERSION",
32
+ "demo/README.md",
33
+ "demo/config/mongoid.yml",
34
+ "demo/instagram.graffle",
35
+ "demo/instagram.png",
36
+ "demo/showoff.css",
37
+ "demo/showoff.md",
32
38
  "gemfiles/mongoid2.gemfile",
33
39
  "gemfiles/mongoid3.gemfile",
34
40
  "lib/mongoid-locker.rb",
data/spec/database.yml CHANGED
@@ -1,4 +1,5 @@
1
1
  test:
2
+ # for Mongoid 2
2
3
  host: localhost
3
4
  database: mongoid_locker_test
4
5
 
@@ -14,7 +14,7 @@ describe Mongoid::Locker do
14
14
  field :account_balance, :type => Integer # easier to test than Float
15
15
  end
16
16
 
17
- @user = User.create!
17
+ @user = User.create! :account_balance => 20
18
18
  end
19
19
 
20
20
  after do
@@ -94,7 +94,7 @@ describe Mongoid::Locker do
94
94
  end
95
95
 
96
96
  @user.account_balance.should eq(10)
97
- User.first.account_balance.should be_nil
97
+ User.first.account_balance.should eq(20)
98
98
  end
99
99
 
100
100
  it "should handle errors gracefully" do
@@ -153,6 +153,22 @@ describe Mongoid::Locker do
153
153
  end
154
154
  end
155
155
 
156
+ it "should reload the document if it needs to wait for a lock" do
157
+ User.timeout_lock_after 1
158
+
159
+ @user.with_lock do
160
+ user_dup = User.first
161
+
162
+ @user.account_balance = 10
163
+ @user.save!
164
+
165
+ user_dup.account_balance.should eq(20)
166
+ user_dup.with_lock :wait => true do
167
+ user_dup.account_balance.should eq(10)
168
+ end
169
+ end
170
+ end
171
+
156
172
  it "should succeed for subclasses" do
157
173
  class Admin < User
158
174
  end
data/spec/spec_helper.rb CHANGED
@@ -11,5 +11,10 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
11
11
 
12
12
  RSpec.configure do |config|
13
13
  Mongoid.load! File.join(File.dirname(__FILE__), 'database.yml')
14
- Mongoid.logger.level = Logger::WARN
14
+
15
+ # use to check the query conditions
16
+ if ENV['LOG']
17
+ Mongoid.logger.level = Logger::DEBUG
18
+ Moped.logger.level = Logger::DEBUG if defined? Moped
19
+ end
15
20
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-locker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-27 00:00:00.000000000 Z
12
+ date: 2012-11-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mongoid
@@ -166,6 +166,12 @@ files:
166
166
  - README.md
167
167
  - Rakefile
168
168
  - VERSION
169
+ - demo/README.md
170
+ - demo/config/mongoid.yml
171
+ - demo/instagram.graffle
172
+ - demo/instagram.png
173
+ - demo/showoff.css
174
+ - demo/showoff.md
169
175
  - gemfiles/mongoid2.gemfile
170
176
  - gemfiles/mongoid3.gemfile
171
177
  - lib/mongoid-locker.rb
@@ -190,7 +196,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
190
196
  version: '0'
191
197
  segments:
192
198
  - 0
193
- hash: 2610862896755729046
199
+ hash: -4115924438345576931
194
200
  required_rubygems_version: !ruby/object:Gem::Requirement
195
201
  none: false
196
202
  requirements: