mongoid-locker 0.3.5 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|