marloss 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://travis-ci.org/eredi93/marloss.svg?branch=master)](https://travis-ci.org/eredi93/marloss)
|
4
4
|
[![Gem Version](https://badge.fury.io/rb/marloss.svg)](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
|
+
![rusty-lock](https://user-images.githubusercontent.com/10990391/33243215-aa602a6c-d2d9-11e7-8fc6-d4a0c2a5b30d.jpg)
|
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
|