marloss 0.1.1 → 0.2.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/.gitignore +1 -0
- data/CHANGELOG.md +9 -0
- data/README.md +53 -3
- data/lib/marloss.rb +56 -0
- data/lib/marloss/error.rb +10 -2
- data/lib/marloss/locker.rb +4 -0
- data/lib/marloss/store.rb +14 -0
- data/lib/marloss/version.rb +1 -1
- 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: 11111f0e9d75f96a957474f886c63db4686e0329c4a4457beafb0a0aae83be2c
|
4
|
+
data.tar.gz: fea9eec8c522ca462ede12c94aa7228cf56ae6d9540d0e8b4925e3249e88c71c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69787108adc8ef5f2c8da6cb553d3e4033492c076267af966c9ea80d8b2d25e3175a809561327dc2f13eb13bfd08e02e38827258e94a9dcb40e732ade97f3421
|
7
|
+
data.tar.gz: cab2f65c3b4191a63c6bd30b461a3b82412dbac16267ee8ca1e0272fc9859c6f97c2aad276df371c2952cc222dbf83fb632799b0bbc4ec2594cb788973c1a411
|
data/.gitignore
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
## 0.2.0 29/11/2017
|
2
|
+
|
3
|
+
IMPROVEMENTS:
|
4
|
+
|
5
|
+
* Add the possibility to include `Marloss`. This adds some healpers that makes it really easy to use the lock in your class
|
6
|
+
|
7
|
+
BUG FIXES:
|
8
|
+
|
9
|
+
* Add the possibility of deleting the lock, it was documented but never implemented
|
data/README.md
CHANGED
@@ -3,16 +3,66 @@
|
|
3
3
|
[](https://travis-ci.org/eredi93/marloss)
|
4
4
|
[](http://badge.fury.io/rb/marloss)
|
5
5
|
|
6
|
-
Marloss is a general DynamoDB-based
|
6
|
+
Marloss is a general DynamoDB-based lock implementation.
|
7
|
+
|
8
|
+

|
7
9
|
|
8
10
|
### Installation
|
9
11
|
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem "marloss"
|
16
|
+
```
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
```sh
|
21
|
+
$ bundle
|
22
|
+
```
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
|
10
26
|
```sh
|
11
|
-
gem install marloss
|
27
|
+
$ gem install marloss
|
12
28
|
```
|
13
29
|
|
14
30
|
### Usage
|
15
31
|
|
32
|
+
Marloss can be use as module, with some useful heplers, or plain for more specific use cases
|
33
|
+
|
34
|
+
#### Module
|
35
|
+
|
36
|
+
Include the module to your class and set the options
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
class MyClass
|
40
|
+
|
41
|
+
include Marloss
|
42
|
+
|
43
|
+
marloss_options table: "my_table", hash_key: "ID"
|
44
|
+
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
now you can simply wrap the code that needs to be locked
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
with_marloss_locker("my_lock")
|
52
|
+
# execute code
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
if you have a long running task and you need to make sure you don't lose the lock
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
with_refreshed_marloss_locker("my_lock")
|
60
|
+
# execute code
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
#### Plain
|
65
|
+
|
16
66
|
Firstly, we need to initialize a lock store:
|
17
67
|
|
18
68
|
```ruby
|
@@ -39,7 +89,7 @@ locker.with_refreshed_lock do
|
|
39
89
|
end
|
40
90
|
|
41
91
|
# delete the lock
|
42
|
-
locker.
|
92
|
+
locker.release_lock
|
43
93
|
```
|
44
94
|
|
45
95
|
### Testing
|
data/lib/marloss.rb
CHANGED
@@ -17,4 +17,60 @@ module Marloss
|
|
17
17
|
@logger = logger
|
18
18
|
end
|
19
19
|
|
20
|
+
def self.included(base)
|
21
|
+
base.define_singleton_method(:marloss_options) do |opts|
|
22
|
+
if opts[:table].nil?
|
23
|
+
raise(MissingParameterError, "DynamoDB Hash Key not set")
|
24
|
+
elsif opts[:hash_key].nil?
|
25
|
+
raise(MissingParameterError, "DynamoDB Table not set")
|
26
|
+
end
|
27
|
+
|
28
|
+
define_method(:marloss_options_hash) { opts }
|
29
|
+
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
33
|
+
base.send(:include, InstanceMethods)
|
34
|
+
end
|
35
|
+
|
36
|
+
module InstanceMethods
|
37
|
+
|
38
|
+
def marloss_store
|
39
|
+
@marloss_store ||=begin
|
40
|
+
table = marloss_options_hash[:table]
|
41
|
+
hash_key = marloss_options_hash[:hash_key]
|
42
|
+
options = marloss_options_hash.reject do |k, v|
|
43
|
+
k == :table || k == :hash_key
|
44
|
+
end
|
45
|
+
|
46
|
+
Store.new(table, hash_key, options)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def marloss_locker(name)
|
51
|
+
Locker.new(marloss_store, name)
|
52
|
+
end
|
53
|
+
|
54
|
+
def with_marloss_locker(name, opts = {})
|
55
|
+
locker = marloss_locker(name)
|
56
|
+
|
57
|
+
locker.wait_until_lock_obtained(opts)
|
58
|
+
|
59
|
+
yield
|
60
|
+
|
61
|
+
locker.release_lock
|
62
|
+
end
|
63
|
+
|
64
|
+
def with_refreshed_marloss_locker(name, opts = {})
|
65
|
+
locker = marloss_locker(name)
|
66
|
+
|
67
|
+
locker.wait_until_lock_obtained(opts)
|
68
|
+
|
69
|
+
locker.with_refreshed_lock { yield }
|
70
|
+
|
71
|
+
locker.release_lock
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
20
76
|
end
|
data/lib/marloss/error.rb
CHANGED
@@ -1,9 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
#
|
3
3
|
module Marloss
|
4
|
-
|
4
|
+
|
5
|
+
class Error < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
class LockNotObtainedError < Error
|
5
9
|
end
|
6
10
|
|
7
|
-
class LockNotRefreshedError <
|
11
|
+
class LockNotRefreshedError < Error
|
8
12
|
end
|
13
|
+
|
14
|
+
class MissingParameterError < Error
|
15
|
+
end
|
16
|
+
|
9
17
|
end
|
data/lib/marloss/locker.rb
CHANGED
data/lib/marloss/store.rb
CHANGED
@@ -32,7 +32,9 @@ module Marloss
|
|
32
32
|
},
|
33
33
|
table_name: table
|
34
34
|
)
|
35
|
+
|
35
36
|
Marloss.logger.info("DynamoDB table created successfully")
|
37
|
+
|
36
38
|
client.update_time_to_live(
|
37
39
|
table_name: table,
|
38
40
|
time_to_live_specification: {
|
@@ -40,11 +42,13 @@ module Marloss
|
|
40
42
|
attribute_name: "Expires"
|
41
43
|
}
|
42
44
|
)
|
45
|
+
|
43
46
|
Marloss.logger.info("DynamoDB table TTL configured successfully")
|
44
47
|
end
|
45
48
|
|
46
49
|
def delete_table
|
47
50
|
client.delete_table(table_name: table)
|
51
|
+
|
48
52
|
Marloss.logger.info("DynamoDB table deleted successfully")
|
49
53
|
end
|
50
54
|
|
@@ -66,9 +70,12 @@ module Marloss
|
|
66
70
|
},
|
67
71
|
condition_expression: "attribute_not_exists(#{hash_key}) OR #E < :now OR #P = :process_id"
|
68
72
|
)
|
73
|
+
|
69
74
|
Marloss.logger.info("Lock for #{name} created successfully, will expire in #{ttl} seconds")
|
70
75
|
rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException => e
|
76
|
+
|
71
77
|
Marloss.logger.error("Failed to create lock for #{name}")
|
78
|
+
|
72
79
|
raise(LockNotObtainedError, e.message)
|
73
80
|
end
|
74
81
|
|
@@ -88,12 +95,19 @@ module Marloss
|
|
88
95
|
update_expression: "SET #E = :expires",
|
89
96
|
condition_expression: "attribute_exists(#{hash_key}) AND (#E < :now OR #P = :process_id)"
|
90
97
|
)
|
98
|
+
|
91
99
|
Marloss.logger.info("Lock for #{name} refreshed successfully, will expire in #{ttl} seconds")
|
92
100
|
rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException => e
|
101
|
+
|
93
102
|
Marloss.logger.error("Failed to refresh lock for #{name}")
|
103
|
+
|
94
104
|
raise(LockNotRefreshedError, e.message)
|
95
105
|
end
|
96
106
|
|
107
|
+
def delete_lock(name)
|
108
|
+
client.delete_item(key: { hash_key => name }, table_name: table)
|
109
|
+
end
|
110
|
+
|
97
111
|
private def process_id
|
98
112
|
hostname = `hostname`.chomp
|
99
113
|
pid = Process.pid
|
data/lib/marloss/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: marloss
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jacopo Scrinzi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-11-
|
11
|
+
date: 2017-11-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-dynamodb
|
@@ -74,6 +74,7 @@ extra_rdoc_files: []
|
|
74
74
|
files:
|
75
75
|
- ".gitignore"
|
76
76
|
- ".travis.yml"
|
77
|
+
- CHANGELOG.md
|
77
78
|
- CONTRIBUTING.md
|
78
79
|
- Gemfile
|
79
80
|
- LICENSE.md
|