mongoid-locking 1.1.1 → 1.3.0
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 +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +15 -1
- data/Gemfile.lock +7 -9
- data/README.md +53 -3
- data/lib/mongoid/locking/retry.rb +67 -0
- data/lib/mongoid/locking/version.rb +1 -1
- data/lib/mongoid/locking.rb +13 -6
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 896cdc8de472341f894c24adbedf92e07bc88a0d13c602f75233e052391d505b
|
4
|
+
data.tar.gz: 545fb0a99ca2280c696ec2eccab487a1f6b8a5bd898be20707f2cb3406296ff8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51aa29f8661bb0e4c257c22137eff2342b308deb47c8c1c1b68ffeaec32767985e55741011978d427c2333f422abe18e4731a0e91bab186df71180d8e6734e15
|
7
|
+
data.tar.gz: 3b23274fb66538af4dfd938af8f6824dce5d3439f82cbabf6041d15d6f36f1d1fa4e37195d3e5ef3151bae04014d51577bb77ccb5701c44ed7b84b951aeb1ecf
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,18 @@
|
|
1
|
-
## [
|
1
|
+
## [1.3.0]
|
2
|
+
|
3
|
+
- Add: delay between retries for `with_locking` method [#8](https://github.com/fullhealthmedical/mongoid-locking/pull/8)
|
4
|
+
|
5
|
+
## [1.2.0]
|
6
|
+
|
7
|
+
- Add: with_locking method [#6](https://github.com/fullhealthmedical/mongoid-locking/pull/6)
|
8
|
+
|
9
|
+
## [1.1.1]
|
10
|
+
|
11
|
+
- Fix: Fix update embedded association [#5](https://github.com/fullhealthmedical/mongoid-locking/pull/5)
|
12
|
+
|
13
|
+
## [1.1.0]
|
14
|
+
|
15
|
+
- Add: Support for Mongoid 7.3 [#3](https://github.com/fullhealthmedical/mongoid-locking/pull/3)
|
2
16
|
|
3
17
|
## [0.1.0] - 2022-08-03
|
4
18
|
|
data/Gemfile.lock
CHANGED
@@ -1,20 +1,19 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
mongoid-locking (1.
|
4
|
+
mongoid-locking (1.3.0)
|
5
5
|
mongoid (~> 7.2)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
activemodel (
|
11
|
-
activesupport (=
|
12
|
-
activesupport (
|
10
|
+
activemodel (7.0.8)
|
11
|
+
activesupport (= 7.0.8)
|
12
|
+
activesupport (7.0.8)
|
13
13
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
14
14
|
i18n (>= 1.6, < 2)
|
15
15
|
minitest (>= 5.1)
|
16
16
|
tzinfo (~> 2.0)
|
17
|
-
zeitwerk (~> 2.3)
|
18
17
|
ast (2.4.2)
|
19
18
|
bson (4.15.0)
|
20
19
|
byebug (11.1.3)
|
@@ -24,10 +23,10 @@ GEM
|
|
24
23
|
concurrent-ruby (~> 1.0)
|
25
24
|
json (2.6.2)
|
26
25
|
minitest (5.20.0)
|
27
|
-
mongo (2.19.
|
26
|
+
mongo (2.19.3)
|
28
27
|
bson (>= 4.14.1, < 5.0.0)
|
29
|
-
mongoid (7.
|
30
|
-
activemodel (>= 5.1, <
|
28
|
+
mongoid (7.5.4)
|
29
|
+
activemodel (>= 5.1, < 7.1, != 7.0.0)
|
31
30
|
mongo (>= 2.10.5, < 3.0.0)
|
32
31
|
ruby2_keywords (~> 0.0.5)
|
33
32
|
parallel (1.22.1)
|
@@ -69,7 +68,6 @@ GEM
|
|
69
68
|
tzinfo (2.0.6)
|
70
69
|
concurrent-ruby (~> 1.0)
|
71
70
|
unicode-display_width (2.2.0)
|
72
|
-
zeitwerk (2.6.12)
|
73
71
|
|
74
72
|
PLATFORMS
|
75
73
|
arm64-darwin-21
|
data/README.md
CHANGED
@@ -19,7 +19,7 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
19
19
|
|
20
20
|
- Include `Mongoid::Locking` module
|
21
21
|
|
22
|
-
```
|
22
|
+
```ruby
|
23
23
|
class Order
|
24
24
|
include Mongoid::Document
|
25
25
|
include Mongoid::Locking
|
@@ -28,16 +28,66 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
28
28
|
|
29
29
|
- Handle `Mongoid::StaleObjectError` when performing updates
|
30
30
|
|
31
|
-
```
|
31
|
+
```ruby
|
32
32
|
# ...
|
33
33
|
def update_order
|
34
|
-
|
34
|
+
Order.update(attributes)
|
35
35
|
rescue Mongoid::StaleObjectError => e
|
36
36
|
add_error("This order has been changed ...")
|
37
37
|
end
|
38
38
|
end
|
39
39
|
```
|
40
40
|
|
41
|
+
- Use `with_locking` to automatically handle `Mongoid::StaleObjectError`
|
42
|
+
|
43
|
+
By default, `with_locking` will retry the update 3 times in case of a
|
44
|
+
`Mongoid::StaleObjectError`.
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
def process_with_locking
|
48
|
+
Order.with_locking do
|
49
|
+
# Ensure the block is idempotent
|
50
|
+
# Reload object(s) within the block to get the latest changes
|
51
|
+
order.reload
|
52
|
+
# Your code here
|
53
|
+
# ...
|
54
|
+
end
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
Adjust the `max_retries` parameter to control the number of retry attempts in
|
59
|
+
case of a `Mongoid::StaleObjectError`.
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
# ...
|
63
|
+
def update_order
|
64
|
+
order.with_locking(max_retries: 2) do
|
65
|
+
order.update(attributes)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
- Use `with_locking` at the instance level to automatically reload the instance
|
72
|
+
on each retry
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
def process_with_locking
|
76
|
+
order.with_locking do
|
77
|
+
# The instance is automatically reloaded for each retry
|
78
|
+
# Your code here
|
79
|
+
# ...
|
80
|
+
end
|
81
|
+
end
|
82
|
+
````
|
83
|
+
|
84
|
+
The with_locking method at the instance level combines class-level locking with
|
85
|
+
automatic reloading on each retry. This ensures that the instance reflects the
|
86
|
+
latest changes, providing seamless control over optimistic locking.
|
87
|
+
|
88
|
+
NOTE: The `with_locking` method will add a delay between retries to avoid
|
89
|
+
contention. [More info](https://github.com/fullhealthmedical/mongoid-locking/pull/8).
|
90
|
+
|
41
91
|
## Development
|
42
92
|
|
43
93
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Mongoid
|
2
|
+
module Locking
|
3
|
+
##
|
4
|
+
# Gives the ability to retry a block of code a specified number of times
|
5
|
+
# when a Mongoid::StaleObjectError is raised.
|
6
|
+
module Retry
|
7
|
+
def self.included(base)
|
8
|
+
base.extend(ClassMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# Retries the block of code a specified number of times when a
|
13
|
+
# Mongoid::StaleObjectError is raised.
|
14
|
+
#
|
15
|
+
# This method will reload the document before each block execution.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# person = Person.find(existing.id)
|
19
|
+
# person.with_locking do
|
20
|
+
# person.update!(name: "Person 1 updated")
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# @param [ Integer ] max_retries The maximum number of times to retry
|
24
|
+
#
|
25
|
+
# @return [ Object ] The result of the block
|
26
|
+
def with_locking(max_retries: 3)
|
27
|
+
self.class.with_locking(max_retries: max_retries) do
|
28
|
+
reload
|
29
|
+
yield
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods # :nodoc:
|
34
|
+
##
|
35
|
+
# Retries the block of code a specified number of times when a
|
36
|
+
# Mongoid::StaleObjectError is raised.
|
37
|
+
#
|
38
|
+
# @example
|
39
|
+
# Person.with_locking do
|
40
|
+
# person = Person.find(existing.id)
|
41
|
+
# Person.update!(name: "Person 1 updated")
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# @param [ Integer ] max_retries The maximum number of times to retry
|
45
|
+
#
|
46
|
+
# @return [ Object ] The result of the block
|
47
|
+
def with_locking(max_retries: 3)
|
48
|
+
retries = 0
|
49
|
+
|
50
|
+
begin
|
51
|
+
yield
|
52
|
+
rescue Mongoid::StaleObjectError
|
53
|
+
retries += 1
|
54
|
+
raise if retries > max_retries
|
55
|
+
|
56
|
+
sleep Mongoid::Locking.backoff_algorithm(retries)
|
57
|
+
retry
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def backoff_algorithm(retries)
|
62
|
+
(2 + rand)**retries
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/mongoid/locking.rb
CHANGED
@@ -9,6 +9,7 @@ require_relative "locking/reloadable"
|
|
9
9
|
require_relative "locking/persistable/creatable"
|
10
10
|
require_relative "locking/persistable/updatable"
|
11
11
|
require_relative "locking/persistable"
|
12
|
+
require_relative "locking/retry"
|
12
13
|
|
13
14
|
module Mongoid
|
14
15
|
##
|
@@ -16,13 +17,19 @@ module Mongoid
|
|
16
17
|
#
|
17
18
|
# @since 0.1.0
|
18
19
|
module Locking
|
19
|
-
|
20
|
-
base
|
21
|
-
|
20
|
+
class << self
|
21
|
+
def included(base)
|
22
|
+
base.field :lock_version, type: Integer
|
23
|
+
base.before_create { self.lock_version = 0 }
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
|
25
|
+
base.include Mongoid::Locking::Selectable
|
26
|
+
base.include Mongoid::Locking::Reloadable
|
27
|
+
base.include Mongoid::Locking::Retry
|
28
|
+
end
|
29
|
+
|
30
|
+
def backoff_algorithm(retries)
|
31
|
+
(2**retries) + rand
|
32
|
+
end
|
26
33
|
end
|
27
34
|
end
|
28
35
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid-locking
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rodrigo RA
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mongoid
|
@@ -121,6 +121,7 @@ files:
|
|
121
121
|
- lib/mongoid/locking/persistable/creatable.rb
|
122
122
|
- lib/mongoid/locking/persistable/updatable.rb
|
123
123
|
- lib/mongoid/locking/reloadable.rb
|
124
|
+
- lib/mongoid/locking/retry.rb
|
124
125
|
- lib/mongoid/locking/selectable.rb
|
125
126
|
- lib/mongoid/locking/version.rb
|
126
127
|
- lib/mongoid/stale_object_error.rb
|