mongoid-locker 0.2.0 → 0.2.1

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.
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: