mongoid-locker 0.3.5 → 2.0.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.
- checksums.yaml +5 -5
- data/.gitignore +3 -8
- data/.rspec +1 -2
- data/.rubocop.yml +1 -6
- data/.rubocop_todo.yml +117 -36
- data/.travis.yml +35 -15
- data/CHANGELOG.md +34 -1
- data/Dangerfile +3 -1
- data/Gemfile +16 -19
- data/Guardfile +15 -6
- data/LICENSE.txt +1 -1
- data/README.md +126 -21
- data/RELEASING.md +68 -0
- data/Rakefile +2 -2
- data/UPGRADING.md +37 -0
- data/lib/config/locales/en.yml +9 -0
- data/lib/mongoid-locker.rb +10 -1
- data/lib/mongoid/locker.rb +250 -105
- data/lib/mongoid/locker/errors.rb +46 -0
- data/lib/mongoid/locker/version.rb +3 -1
- data/lib/mongoid/locker/wrapper.rb +120 -14
- data/mongoid-locker.gemspec +16 -16
- metadata +15 -32
- data/.document +0 -5
- data/demo/README.md +0 -10
- data/demo/config/mongoid.yml +0 -6
- data/demo/instagram.graffle +0 -1012
- data/demo/instagram.png +0 -0
- data/demo/showoff.css +0 -16
- data/demo/showoff.md +0 -159
- data/lib/mongoid/locker/wrapper2.rb +0 -26
- data/lib/mongoid/locker/wrapper3.rb +0 -26
- data/lib/mongoid/locker/wrapper4.rb +0 -22
- data/lib/mongoid/locker/wrapper5.rb +0 -27
- data/lib/mongoid/locker/wrapper6.rb +0 -29
data/RELEASING.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
Releasing Mongoid::Locker
|
2
|
+
=========================
|
3
|
+
|
4
|
+
There're no particular rules about when to release mongoid-locker. Release bug fixes frequently, features not so frequently and breaking API changes rarely.
|
5
|
+
|
6
|
+
### Release
|
7
|
+
|
8
|
+
Run tests, check that all tests succeed locally.
|
9
|
+
|
10
|
+
```
|
11
|
+
bundle install
|
12
|
+
bundle exec rake
|
13
|
+
```
|
14
|
+
|
15
|
+
Check that the last build succeeded in [Travis CI](https://travis-ci.org/mongoid/mongoid-locker) for all supported platforms.
|
16
|
+
|
17
|
+
Check the version, if needed modify [lib/mongoid/locker/version.rb](lib/mongoid/locker/version.rb).
|
18
|
+
|
19
|
+
* Increment the third number if the release has bug fixes and/or very minor features, only (eg. change `0.5.1` to `0.5.2`).
|
20
|
+
* Increment the second number if the release contains major features or breaking API changes (eg. change `0.5.1` to `0.4.0`).
|
21
|
+
|
22
|
+
Change "Next Release" in [CHANGELOG.md](CHANGELOG.md) to the new version.
|
23
|
+
|
24
|
+
```
|
25
|
+
### 0.4.0 (2014-01-27)
|
26
|
+
```
|
27
|
+
|
28
|
+
Remove the line with "Your contribution here.", since there will be no more contributions to this release.
|
29
|
+
|
30
|
+
Commit your changes.
|
31
|
+
|
32
|
+
```
|
33
|
+
git add CHANGELOG.md lib/mongoid-locker/version.rb
|
34
|
+
git commit -m "Preparing for release, 0.4.0."
|
35
|
+
git push origin master
|
36
|
+
```
|
37
|
+
|
38
|
+
Release.
|
39
|
+
|
40
|
+
```
|
41
|
+
$ bundle exec rake release
|
42
|
+
|
43
|
+
mongoid-locker 0.4.0 built to pkg/mongoid-locker-0.4.0.gem.
|
44
|
+
Tagged v0.4.0.
|
45
|
+
Pushed git commits and tags.
|
46
|
+
Pushed mongoid-locker 0.4.0 to rubygems.org.
|
47
|
+
```
|
48
|
+
|
49
|
+
### Prepare for the Next Version
|
50
|
+
|
51
|
+
Add the next release to [CHANGELOG.md](CHANGELOG.md).
|
52
|
+
|
53
|
+
```
|
54
|
+
Next Release
|
55
|
+
============
|
56
|
+
|
57
|
+
* Your contribution here.
|
58
|
+
```
|
59
|
+
|
60
|
+
Increment the minor version, modify [lib/mongoid-locker/version.rb](lib/mongoid-locker/version.rb).
|
61
|
+
|
62
|
+
Commit your changes.
|
63
|
+
|
64
|
+
```
|
65
|
+
git add CHANGELOG.md lib/mongoid-locker/version.rb
|
66
|
+
git commit -m "Preparing for next release, 0.4.1."
|
67
|
+
git push origin master
|
68
|
+
```
|
data/Rakefile
CHANGED
data/UPGRADING.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
## Upgrading Mongoid-Locker
|
2
|
+
|
3
|
+
## Upgrading to 2.0.0
|
4
|
+
|
5
|
+
Mongoid-Locker supports only `5`, `6` and `7` versions of Mongoid.
|
6
|
+
Since this version `Mongoid::Locker` uses unique name of locking and time is set by MongoDB. `Mongoid::Locker` no longer uses `locked_until` field and this field may be deleted with `User.all.unset(:locked_until)`. You must define new `locking_name` field of `String` type.
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
class User
|
10
|
+
include Mongoid::Document
|
11
|
+
include Mongoid::Locker
|
12
|
+
|
13
|
+
field :locking_name, type: String
|
14
|
+
field :locked_at, type: Time
|
15
|
+
end
|
16
|
+
```
|
17
|
+
|
18
|
+
The options `:timeout` and `retry_sleep` of `#with_lock` method was deprecated and have no effect. For details see [RubyDoc.info](https://www.rubydoc.info/gems/mongoid-locker/2.0.0/Mongoid/Locker#with_lock-instance_method).
|
19
|
+
If you handle `Mongoid::Locker::LockError` error then this error should be renamed to `Mongoid::Locker::Errors::DocumentCouldNotGetLock`.
|
20
|
+
|
21
|
+
### Upgrading to 1.0.0
|
22
|
+
|
23
|
+
`Mongoid::Locker` no longer defines `locked_at` and `locked_until` fields when included. You must define these fields manually.
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
class User
|
27
|
+
include Mongoid::Document
|
28
|
+
include Mongoid::Locker
|
29
|
+
|
30
|
+
field :locked_at, type: Time
|
31
|
+
field :locked_until, type: Time
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
You can customize the fields used with a `locker` class method or via a global `configure`. See [Customizable :locked_at and :locked_until field names](https://github.com/mongoid/mongoid-locker#customizable-locked_at-and-locked_until-field-names) for more information.
|
36
|
+
|
37
|
+
See [#55](https://github.com/mongoid/mongoid-locker/pull/55) for more information.
|
data/lib/mongoid-locker.rb
CHANGED
@@ -1,2 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'mongoid'
|
2
|
-
|
4
|
+
|
5
|
+
require 'mongoid/locker'
|
6
|
+
require 'mongoid/locker/version'
|
7
|
+
require 'mongoid/locker/wrapper'
|
8
|
+
require 'mongoid/locker/errors'
|
9
|
+
|
10
|
+
# Load english locale by default.
|
11
|
+
I18n.load_path << File.join(File.dirname(__FILE__), 'config/locales', 'en.yml')
|
data/lib/mongoid/locker.rb
CHANGED
@@ -1,168 +1,313 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require 'securerandom'
|
3
5
|
|
4
6
|
module Mongoid
|
5
7
|
module Locker
|
6
|
-
|
7
|
-
|
8
|
+
class << self
|
9
|
+
# Available parameters for +Mongoid::Locker+ module, a class where the module is included and it's instances.
|
10
|
+
MODULE_METHODS = %i[
|
11
|
+
locking_name_field
|
12
|
+
locked_at_field
|
13
|
+
maximum_backoff
|
14
|
+
lock_timeout
|
15
|
+
locker_write_concern
|
16
|
+
backoff_algorithm
|
17
|
+
locking_name_generator
|
18
|
+
].freeze
|
19
|
+
|
20
|
+
attr_accessor(*MODULE_METHODS)
|
21
|
+
|
22
|
+
# Generates secure random string of +name#attempt+ format.
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# Mongoid::Locker.secure_locking_name(doc, { attempt: 1 })
|
26
|
+
# #=> "zLmulhOy9yn_NE886OWNYw#1"
|
27
|
+
#
|
28
|
+
# @param doc [Mongoid::Document]
|
29
|
+
# @param opts [Hash] (see #with_lock)
|
30
|
+
# @return [String]
|
31
|
+
def secure_locking_name(_doc, opts)
|
32
|
+
"#{SecureRandom.urlsafe_base64}##{opts[:attempt]}"
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns random number of seconds depend on passed options.
|
36
|
+
#
|
37
|
+
# @example
|
38
|
+
# Mongoid::Locker.exponential_backoff(doc, { attempt: 0 })
|
39
|
+
# #=> 1.2280675023095662
|
40
|
+
# Mongoid::Locker.exponential_backoff(doc, { attempt: 1 })
|
41
|
+
# #=> 2.901641863236713
|
42
|
+
# Mongoid::Locker.exponential_backoff(doc, { attempt: 2 })
|
43
|
+
# #=> 4.375030664612267
|
44
|
+
#
|
45
|
+
# @param _doc [Mongoid::Document]
|
46
|
+
# @param opts [Hash] (see #with_lock)
|
47
|
+
# @return [Float]
|
48
|
+
def exponential_backoff(_doc, opts)
|
49
|
+
2**opts[:attempt] + rand
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns time in seconds remaining to complete the lock of the provided document. Makes requests to the database.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# Mongoid::Locker.locked_at_backoff(doc, opts)
|
56
|
+
# #=> 2.32422359
|
57
|
+
#
|
58
|
+
# @param doc [Mongoid::Document]
|
59
|
+
# @param opts [Hash] (see #with_lock)
|
60
|
+
# @return [Float | Integer]
|
61
|
+
# @return [0] if the provided document is not locked
|
62
|
+
def locked_at_backoff(doc, opts)
|
63
|
+
return doc.maximum_backoff if opts[:attempt] * doc.lock_timeout >= doc.maximum_backoff
|
64
|
+
|
65
|
+
locked_at = Wrapper.locked_at(doc).to_f
|
66
|
+
return 0 unless locked_at > 0
|
67
|
+
|
68
|
+
current_time = Wrapper.current_mongodb_time(doc.class).to_f
|
69
|
+
delay = doc.lock_timeout - (current_time - locked_at)
|
70
|
+
|
71
|
+
delay < 0 ? 0 : delay + rand
|
72
|
+
end
|
73
|
+
|
74
|
+
# Sets configuration using a block.
|
75
|
+
#
|
76
|
+
# @example
|
77
|
+
# Mongoid::Locker.configure do |config|
|
78
|
+
# config.locking_name_field = :locking_name
|
79
|
+
# config.locked_at_field = :locked_at
|
80
|
+
# config.lock_timeout = 5
|
81
|
+
# config.locker_write_concern = { w: 1 }
|
82
|
+
# config.maximum_backoff = 60.0
|
83
|
+
# config.backoff_algorithm = :exponential_backoff
|
84
|
+
# config.locking_name_generator = :secure_locking_name
|
85
|
+
# end
|
86
|
+
def configure
|
87
|
+
yield(self) if block_given?
|
88
|
+
end
|
89
|
+
|
90
|
+
# Resets to default configuration.
|
91
|
+
#
|
92
|
+
# @example
|
93
|
+
# Mongoid::Locker.reset!
|
94
|
+
def reset!
|
95
|
+
# The parameters used by default.
|
96
|
+
self.locking_name_field = :locking_name
|
97
|
+
self.locked_at_field = :locked_at
|
98
|
+
self.lock_timeout = 5
|
99
|
+
self.locker_write_concern = { w: 1 }
|
100
|
+
self.maximum_backoff = 60.0
|
101
|
+
self.backoff_algorithm = :exponential_backoff
|
102
|
+
self.locking_name_generator = :secure_locking_name
|
103
|
+
end
|
104
|
+
|
105
|
+
# @api private
|
106
|
+
def included(klass)
|
107
|
+
klass.extend(Forwardable) unless klass.ancestors.include?(Forwardable)
|
108
|
+
|
109
|
+
klass.extend ClassMethods
|
110
|
+
klass.singleton_class.instance_eval { attr_accessor(*MODULE_METHODS) }
|
111
|
+
|
112
|
+
klass.locking_name_field = locking_name_field
|
113
|
+
klass.locked_at_field = locked_at_field
|
114
|
+
klass.lock_timeout = lock_timeout
|
115
|
+
klass.locker_write_concern = locker_write_concern
|
116
|
+
klass.maximum_backoff = maximum_backoff
|
117
|
+
klass.backoff_algorithm = backoff_algorithm
|
118
|
+
klass.locking_name_generator = locking_name_generator
|
119
|
+
|
120
|
+
klass.def_delegators(klass, *MODULE_METHODS)
|
121
|
+
klass.singleton_class.delegate(*(methods(false) - MODULE_METHODS.flat_map { |method| [method, "#{method}=".to_sym] } - %i[included reset! configure]), to: self)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
reset!
|
8
126
|
|
9
127
|
module ClassMethods
|
10
128
|
# A scope to retrieve all locked documents in the collection.
|
11
129
|
#
|
130
|
+
# @example
|
131
|
+
# Account.count
|
132
|
+
# #=> 1717
|
133
|
+
# Account.locked.count
|
134
|
+
# #=> 17
|
135
|
+
#
|
12
136
|
# @return [Mongoid::Criteria]
|
13
137
|
def locked
|
14
|
-
where
|
138
|
+
where(
|
139
|
+
'$and': [
|
140
|
+
{ locking_name_field => { '$exists': true, '$ne': nil } },
|
141
|
+
{ locked_at_field => { '$exists': true, '$ne': nil } },
|
142
|
+
{ '$where': "new Date() - this.#{locked_at_field} < #{lock_timeout * 1000}" }
|
143
|
+
]
|
144
|
+
)
|
15
145
|
end
|
16
146
|
|
17
147
|
# A scope to retrieve all unlocked documents in the collection.
|
18
148
|
#
|
149
|
+
# @example
|
150
|
+
# Account.count
|
151
|
+
# #=> 1717
|
152
|
+
# Account.unlocked.count
|
153
|
+
# #=> 1700
|
154
|
+
#
|
19
155
|
# @return [Mongoid::Criteria]
|
20
156
|
def unlocked
|
21
|
-
|
157
|
+
where(
|
158
|
+
'$or': [
|
159
|
+
{
|
160
|
+
'$or': [
|
161
|
+
{ locking_name_field => { '$exists': false } },
|
162
|
+
{ locked_at_field => { '$exists': false } }
|
163
|
+
]
|
164
|
+
},
|
165
|
+
{
|
166
|
+
'$or': [
|
167
|
+
{ locking_name_field => { '$eq': nil } },
|
168
|
+
{ locked_at_field => { '$eq': nil } }
|
169
|
+
]
|
170
|
+
},
|
171
|
+
{
|
172
|
+
'$where': "new Date() - this.#{locked_at_field} >= #{lock_timeout * 1000}"
|
173
|
+
}
|
174
|
+
]
|
175
|
+
)
|
22
176
|
end
|
23
177
|
|
24
|
-
#
|
178
|
+
# Unlock all locked documents in the collection. Sets locking_name_field and locked_at_field fields to nil. Returns number of unlocked documents.
|
25
179
|
#
|
26
|
-
# @
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
# Retrieve the lock timeout default for this class.
|
180
|
+
# @example
|
181
|
+
# Account.unlock_all
|
182
|
+
# #=> 17
|
183
|
+
# Account.locked.unlock_all
|
184
|
+
# #=> 0
|
33
185
|
#
|
34
|
-
# @return [
|
35
|
-
def
|
36
|
-
|
37
|
-
@lock_timeout || 5
|
186
|
+
# @return [Integer]
|
187
|
+
def unlock_all
|
188
|
+
update_all('$set': { locking_name_field => nil, locked_at_field => nil }).modified_count
|
38
189
|
end
|
39
|
-
end
|
40
190
|
|
41
|
-
|
42
|
-
|
43
|
-
|
191
|
+
# Sets configuration for this class.
|
192
|
+
#
|
193
|
+
# @example
|
194
|
+
# locker locking_name_field: :locker_locking_name,
|
195
|
+
# locked_at_field: :locker_locked_at,
|
196
|
+
# lock_timeout: 3,
|
197
|
+
# locker_write_concern: { w: 1 },
|
198
|
+
# maximum_backoff: 30.0,
|
199
|
+
# backoff_algorithm: :locked_at_backoff,
|
200
|
+
# locking_name_generator: :custom_locking_name
|
201
|
+
#
|
202
|
+
# @param locking_name_field [Symbol]
|
203
|
+
# @param locked_at_field [Symbol]
|
204
|
+
# @param maximum_backoff [Float, Integer]
|
205
|
+
# @param lock_timeout [Float, Integer]
|
206
|
+
# @param locker_write_concern [Hash]
|
207
|
+
# @param backoff_algorithm [Symbol]
|
208
|
+
# @param locking_name_generator [Symbol]
|
209
|
+
def locker(**params)
|
210
|
+
invalid_parameters = params.keys - Mongoid::Locker.singleton_class.const_get('MODULE_METHODS')
|
211
|
+
raise Mongoid::Locker::Errors::InvalidParameter.new(self.class, invalid_parameters.first) unless invalid_parameters.empty?
|
44
212
|
|
45
|
-
|
46
|
-
|
213
|
+
params.each_pair do |key, value|
|
214
|
+
send("#{key}=", value)
|
215
|
+
end
|
216
|
+
end
|
47
217
|
end
|
48
218
|
|
49
|
-
# Returns whether the document is currently locked or not.
|
219
|
+
# Returns whether the document is currently locked in the database or not.
|
220
|
+
#
|
221
|
+
# @example
|
222
|
+
# document.locked?
|
223
|
+
# #=> false
|
50
224
|
#
|
51
225
|
# @return [Boolean] true if locked, false otherwise
|
52
226
|
def locked?
|
53
|
-
|
227
|
+
persisted? && self.class.where(_id: id).locked.limit(1).count == 1
|
54
228
|
end
|
55
229
|
|
56
230
|
# Returns whether the current instance has the lock or not.
|
57
231
|
#
|
232
|
+
# @example
|
233
|
+
# document.has_lock?
|
234
|
+
# #=> false
|
235
|
+
#
|
58
236
|
# @return [Boolean] true if locked, false otherwise
|
59
237
|
def has_lock?
|
60
|
-
|
238
|
+
@has_lock || false
|
61
239
|
end
|
62
240
|
|
63
|
-
#
|
241
|
+
# Executes the provided code once the document has been successfully locked. Otherwise, raises error after the number of retries to lock the document is exhausted or it is reached {ClassMethods#maximum_backoff} limit (depending what comes first).
|
242
|
+
#
|
243
|
+
# @example
|
244
|
+
# document.with_lock(reload: true, retries: 3) do
|
245
|
+
# document.quantity = 17
|
246
|
+
# document.save!
|
247
|
+
# end
|
64
248
|
#
|
65
249
|
# @param [Hash] opts for the locking mechanism
|
66
|
-
# @option opts [Fixnum] :
|
67
|
-
# @option opts [
|
68
|
-
# @option opts [
|
69
|
-
# @option opts [
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
opts[:retries] = 1 if opts[:wait]
|
77
|
-
lock(opts)
|
78
|
-
end
|
250
|
+
# @option opts [Fixnum] :retries (INFINITY) If the document is currently locked, the number of times to retry
|
251
|
+
# @option opts [Boolean] :reload (true) After acquiring the lock, reload the document
|
252
|
+
# @option opts [Integer] :attempt (0) Increment with each retry (not accepted by the method)
|
253
|
+
# @option opts [String] :locking_name Generate with each retry (not accepted by the method)
|
254
|
+
def with_lock(**opts)
|
255
|
+
opts = opts.dup
|
256
|
+
opts[:retries] ||= Float::INFINITY
|
257
|
+
opts[:reload] = opts[:reload] != false
|
258
|
+
|
259
|
+
acquire_lock(opts) if persisted? && (had_lock = !has_lock?)
|
79
260
|
|
80
261
|
begin
|
81
262
|
yield
|
82
263
|
ensure
|
83
|
-
unlock if
|
264
|
+
unlock!(opts) if had_lock
|
84
265
|
end
|
85
266
|
end
|
86
267
|
|
87
268
|
protected
|
88
269
|
|
89
|
-
def acquire_lock(opts
|
90
|
-
|
91
|
-
timeout = opts[:timeout] || self.class.lock_timeout
|
92
|
-
expiration = time + timeout
|
93
|
-
|
94
|
-
# lock the document atomically in the DB without persisting entire doc
|
95
|
-
locked = Mongoid::Locker::Wrapper.update(
|
96
|
-
self.class,
|
97
|
-
{
|
98
|
-
:_id => id,
|
99
|
-
'$or' => [
|
100
|
-
# not locked
|
101
|
-
{ locked_until: nil },
|
102
|
-
# expired
|
103
|
-
{ locked_until: { '$lte' => time } }
|
104
|
-
]
|
105
|
-
},
|
270
|
+
def acquire_lock(opts)
|
271
|
+
opts[:attempt] = 0
|
106
272
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
}
|
273
|
+
loop do
|
274
|
+
opts[:locking_name] = self.class.send(locking_name_generator, self, opts)
|
275
|
+
return if lock!(opts)
|
111
276
|
|
112
|
-
|
277
|
+
opts[:attempt] += 1
|
278
|
+
delay = self.class.send(backoff_algorithm, self, opts)
|
113
279
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
self.locked_until = expiration
|
118
|
-
reload unless opts[:reload] == false
|
119
|
-
@has_lock = true
|
120
|
-
else
|
121
|
-
@has_lock = false
|
280
|
+
raise Errors::DocumentCouldNotGetLock.new(self.class, id) if delay >= maximum_backoff || opts[:attempt] >= opts[:retries]
|
281
|
+
|
282
|
+
sleep delay
|
122
283
|
end
|
123
284
|
end
|
124
285
|
|
125
|
-
def lock(opts
|
126
|
-
|
127
|
-
|
128
|
-
attempts_left = opts[:retries] + 1
|
129
|
-
retry_sleep = opts[:retry_sleep]
|
130
|
-
|
131
|
-
loop do
|
132
|
-
return if acquire_lock(opts)
|
133
|
-
|
134
|
-
attempts_left -= 1
|
286
|
+
def lock!(opts)
|
287
|
+
result = Mongoid::Locker::Wrapper.find_and_lock(self, opts)
|
135
288
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
locked_until = Mongoid::Locker::Wrapper.locked_until(self)
|
140
|
-
# the lock might be released since the last check so make another attempt
|
141
|
-
next unless locked_until
|
142
|
-
retry_sleep = locked_until - Time.now
|
143
|
-
end
|
144
|
-
|
145
|
-
sleep retry_sleep if retry_sleep > 0
|
289
|
+
if result
|
290
|
+
if opts[:reload]
|
291
|
+
reload
|
146
292
|
else
|
147
|
-
|
293
|
+
self[locking_name_field] = result[locking_name_field.to_s]
|
294
|
+
self[locked_at_field] = result[locked_at_field.to_s]
|
148
295
|
end
|
296
|
+
|
297
|
+
@has_lock = true
|
298
|
+
else
|
299
|
+
@has_lock = false
|
149
300
|
end
|
150
301
|
end
|
151
302
|
|
152
|
-
def unlock
|
153
|
-
|
154
|
-
Mongoid::Locker::Wrapper.update(
|
155
|
-
self.class,
|
156
|
-
{ _id: id },
|
157
|
-
|
158
|
-
'$set' => {
|
159
|
-
locked_at: nil,
|
160
|
-
locked_until: nil
|
161
|
-
}
|
303
|
+
def unlock!(opts)
|
304
|
+
Mongoid::Locker::Wrapper.find_and_unlock(self, opts)
|
162
305
|
|
163
|
-
|
306
|
+
unless destroyed?
|
307
|
+
self[locking_name_field] = nil
|
308
|
+
self[locked_at_field] = nil
|
309
|
+
end
|
164
310
|
|
165
|
-
self.attributes = { locked_at: nil, locked_until: nil } unless destroyed?
|
166
311
|
@has_lock = false
|
167
312
|
end
|
168
313
|
end
|