Class: Locksy::DynamoDB
- Inherits:
-
BaseLock
show all
- Extended by:
- Forwardable
- Defined in:
- lib/locksy/dynamodb.rb
Class Attribute Summary collapse
Instance Attribute Summary collapse
Attributes inherited from BaseLock
#_clock, #default_expiry, #default_extension, #lock_name, #owner
#default_expiry, #default_extension, #lock_name, #owner
Class Method Summary
collapse
Instance Method Summary
collapse
Methods inherited from BaseLock
shutting_down?, #with_lock
#with_lock
Constructor Details
#initialize(dynamo_client: default_client, table_name: default_table, **_args) ⇒ DynamoDB
Returns a new instance of DynamoDB.
12
13
14
15
16
17
18
19
20
|
# File 'lib/locksy/dynamodb.rb', line 12
def initialize(dynamo_client: default_client, table_name: default_table, **_args)
require 'aws-sdk-dynamodb'
@dynamo_client = dynamo_client
@table_name = table_name
@_timeout_stopper = ConditionVariable.new
@_timeout_mutex = Mutex.new
super
end
|
Class Attribute Details
.default_client ⇒ Object
101
102
103
|
# File 'lib/locksy/dynamodb.rb', line 101
def default_client
@default_client ||= create_client
end
|
.default_table ⇒ Object
97
98
99
|
# File 'lib/locksy/dynamodb.rb', line 97
def default_table
@default_table ||= 'default_locks'
end
|
Instance Attribute Details
#dynamo_client ⇒ Object
Returns the value of attribute dynamo_client.
8
9
10
|
# File 'lib/locksy/dynamodb.rb', line 8
def dynamo_client
@dynamo_client
end
|
#table_name ⇒ Object
Returns the value of attribute table_name.
8
9
10
|
# File 'lib/locksy/dynamodb.rb', line 8
def table_name
@table_name
end
|
Class Method Details
.create_client(**args) ⇒ Object
105
106
107
108
109
|
# File 'lib/locksy/dynamodb.rb', line 105
def create_client(**args)
require 'aws-sdk-dynamodb'
Aws::DynamoDB::Client.new(**args)
end
|
Instance Method Details
#_interrupt_waiting ⇒ Object
116
117
118
|
# File 'lib/locksy/dynamodb.rb', line 116
def _interrupt_waiting
@_timeout_mutex.synchronize { @_timeout_stopper.broadcast }
end
|
#_wait_for_timeout(timeout) ⇒ Object
112
113
114
|
# File 'lib/locksy/dynamodb.rb', line 112
def _wait_for_timeout(timeout)
@_timeout_mutex.synchronize { @_timeout_stopper.wait(@_timeout_mutex, timeout) }
end
|
#create_table ⇒ Object
76
77
78
79
80
81
82
83
84
85
86
87
88
|
# File 'lib/locksy/dynamodb.rb', line 76
def create_table
dynamo_client.create_table(table_name: table_name,
key_schema: [{ attribute_name: 'id', key_type: 'HASH' }],
attribute_definitions: [{ attribute_name: 'id',
attribute_type: 'S' }],
provisioned_throughput: { read_capacity_units: 10,
write_capacity_units: 10 })
rescue Aws::DynamoDB::Errors::ResourceInUseException => ex
unless ex.message == 'Cannot create preexisting table' ||
ex.message.start_with?('Table already exists')
raise ex
end
end
|
#force_unlock! ⇒ Object
90
91
92
|
# File 'lib/locksy/dynamodb.rb', line 90
def force_unlock!
dynamo_client.delete_item(table_name: table_name, key: { id: lock_name })
end
|
#obtain_lock(expire_after: default_expiry, wait_for: nil, **_args) ⇒ Object
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
# File 'lib/locksy/dynamodb.rb', line 22
def obtain_lock(expire_after: default_expiry, wait_for: nil, **_args)
stop_waiting_at = wait_for ? now + wait_for : nil
expire_at = expiry(expire_after)
dynamo_client.put_item \
({ table_name: table_name,
item: { id: lock_name, expires: expire_at, lock_owner: owner },
condition_expression: '(attribute_not_exists(expires) OR expires < :expires) ' \
'OR (attribute_not_exists(lock_owner) OR lock_owner = :owner)',
expression_attribute_values: { ':expires' => now, ':owner' => owner } })
expire_at
rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException
if stop_waiting_at && stop_waiting_at > now
_wait_for_timeout \
( if (current = retrieve_current_lock).nil?
0.1
else
[stop_waiting_at - now, [(current[:expires] - now) / 2, 0.1].max].min
end)
retry unless self.class.shutting_down?
end
raise build_not_owned_error_from_remote
end
|
#refresh_lock(expire_after: default_extension, **_args) ⇒ Object
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
# File 'lib/locksy/dynamodb.rb', line 60
def refresh_lock(expire_after: default_extension, **_args)
expire_at = expiry(expire_after)
dynamo_client.update_item \
({ table_name: table_name,
key: { id: lock_name },
update_expression: 'SET expires = :expires',
condition_expression: 'attribute_exists(expires) AND expires > :now ' \
'AND lock_owner = :owner',
expression_attribute_values: { ':expires' => expire_at,
':owner' => owner,
':now' => now } })
expire_at
rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException
obtain_lock expire_after: expire_after
end
|
#release_lock ⇒ Object
49
50
51
52
53
54
55
56
57
58
|
# File 'lib/locksy/dynamodb.rb', line 49
def release_lock
dynamo_client.delete_item \
({ table_name: table_name,
key: { id: lock_name },
condition_expression: '(attribute_not_exists(lock_owner) OR lock_owner = :owner) ' \
'OR (attribute_not_exists(expires) OR expires < :expires)',
expression_attribute_values: { ':owner' => owner, ':expires' => now } })
rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException
raise build_not_owned_error_from_remote
end
|