aws-sessionstore-dynamodb 2.2.0 → 3.0.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/CHANGELOG.md +15 -0
- data/LICENSE.txt +202 -0
- data/VERSION +1 -1
- data/lib/aws/session_store/dynamo_db/configuration.rb +119 -204
- data/lib/aws/session_store/dynamo_db/errors/base_handler.rb +2 -0
- data/lib/aws/session_store/dynamo_db/errors/default_handler.rb +13 -12
- data/lib/aws/session_store/dynamo_db/errors.rb +27 -0
- data/lib/aws/session_store/dynamo_db/garbage_collection.rb +84 -93
- data/lib/aws/session_store/dynamo_db/locking/base.rb +31 -32
- data/lib/aws/session_store/dynamo_db/locking/null.rb +4 -3
- data/lib/aws/session_store/dynamo_db/locking/pessimistic.rb +32 -20
- data/lib/aws/session_store/dynamo_db/rack_middleware.rb +45 -49
- data/lib/aws/session_store/dynamo_db/table.rb +64 -67
- data/lib/aws-sessionstore-dynamodb.rb +14 -14
- metadata +18 -64
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -6
- data/.github/workflows/ci.yml +0 -39
- data/.gitignore +0 -12
- data/.gitmodules +0 -3
- data/.yardopts +0 -4
- data/CODE_OF_CONDUCT.md +0 -4
- data/CONTRIBUTING.md +0 -61
- data/Gemfile +0 -24
- data/LICENSE +0 -12
- data/README.md +0 -125
- data/Rakefile +0 -35
- data/aws-sessionstore-dynamodb.gemspec +0 -24
- data/doc-src/templates/default/layout/html/footer.erb +0 -6
- data/doc-src/templates/default/layout/html/layout.erb +0 -31
- data/lib/aws/session_store/dynamo_db/invalid_id_error.rb +0 -7
- data/lib/aws/session_store/dynamo_db/lock_wait_timeout_error.rb +0 -7
- data/lib/aws/session_store/dynamo_db/missing_secret_key_error.rb +0 -7
- data/lib/aws/session_store/dynamo_db/version.rb +0 -7
- data/spec/aws/session_store/dynamo_db/app_config.yml +0 -16
- data/spec/aws/session_store/dynamo_db/configuration_spec.rb +0 -81
- data/spec/aws/session_store/dynamo_db/error/default_error_handler_spec.rb +0 -64
- data/spec/aws/session_store/dynamo_db/garbage_collection_spec.rb +0 -158
- data/spec/aws/session_store/dynamo_db/locking/threaded_sessions_spec.rb +0 -96
- data/spec/aws/session_store/dynamo_db/rack_middleware_database_spec.rb +0 -130
- data/spec/aws/session_store/dynamo_db/rack_middleware_spec.rb +0 -148
- data/spec/aws/session_store/dynamo_db/table_spec.rb +0 -48
- data/spec/spec_helper.rb +0 -65
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Aws::SessionStore::DynamoDB::Errors
|
2
4
|
# This class handles errors raised from DynamoDB.
|
3
5
|
class DefaultHandler < Aws::SessionStore::DynamoDB::Errors::BaseHandler
|
@@ -5,38 +7,37 @@ module Aws::SessionStore::DynamoDB::Errors
|
|
5
7
|
HARD_ERRORS = [
|
6
8
|
Aws::DynamoDB::Errors::ResourceNotFoundException,
|
7
9
|
Aws::DynamoDB::Errors::ConditionalCheckFailedException,
|
8
|
-
Aws::SessionStore::DynamoDB::MissingSecretKeyError,
|
9
|
-
Aws::SessionStore::DynamoDB::LockWaitTimeoutError
|
10
|
-
]
|
10
|
+
Aws::SessionStore::DynamoDB::Errors::MissingSecretKeyError,
|
11
|
+
Aws::SessionStore::DynamoDB::Errors::LockWaitTimeoutError
|
12
|
+
].freeze
|
11
13
|
|
12
14
|
# Determines behavior of DefaultErrorHandler
|
13
15
|
# @param [true] raise_errors Pass all errors up the Rack stack.
|
14
16
|
def initialize(raise_errors)
|
17
|
+
super()
|
15
18
|
@raise_errors = raise_errors
|
16
19
|
end
|
17
20
|
|
18
21
|
# Raises {HARD_ERRORS} up the Rack stack.
|
19
22
|
# Places all other errors in Racks error stream.
|
20
23
|
def handle_error(error, env = {})
|
21
|
-
if HARD_ERRORS.include?(error.class) || @raise_errors
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
false
|
26
|
-
end
|
24
|
+
raise error if HARD_ERRORS.include?(error.class) || @raise_errors
|
25
|
+
|
26
|
+
store_error(error, env)
|
27
|
+
false
|
27
28
|
end
|
28
29
|
|
29
30
|
# Sends error to error stream
|
30
31
|
def store_error(error, env = {})
|
31
|
-
env[
|
32
|
+
env['rack.errors'].puts(errors_string(error)) if env
|
32
33
|
end
|
33
34
|
|
34
35
|
# Returns string to be placed in error stream
|
35
36
|
def errors_string(error)
|
36
37
|
str = []
|
37
38
|
str << "Exception occurred: #{error.message}"
|
38
|
-
str <<
|
39
|
-
str += error.backtrace.map {|l| " "
|
39
|
+
str << 'Stack trace:'
|
40
|
+
str += error.backtrace.map { |l| " #{l}" }
|
40
41
|
str.join("\n")
|
41
42
|
end
|
42
43
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aws::SessionStore::DynamoDB::Errors
|
4
|
+
# This error is raised when no secret key is provided.
|
5
|
+
class MissingSecretKeyError < RuntimeError
|
6
|
+
def initialize(msg = 'No secret key provided!')
|
7
|
+
super
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# This error is raised when an invalid session ID is provided.
|
12
|
+
class InvalidIDError < RuntimeError
|
13
|
+
def initialize(msg = 'Corrupt Session ID!')
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# This error is raised when the maximum time spent to acquire lock has been exceeded.
|
19
|
+
class LockWaitTimeoutError < RuntimeError
|
20
|
+
def initialize(msg = 'Maximum time spent to acquire lock has been exceeded!')
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require_relative 'errors/base_handler'
|
27
|
+
require_relative 'errors/default_handler'
|
@@ -1,115 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'aws-sdk-dynamodb'
|
2
4
|
|
3
5
|
module Aws::SessionStore::DynamoDB
|
4
6
|
# Collects and deletes unwanted sessions based on
|
5
7
|
# their creation and update dates.
|
6
8
|
module GarbageCollection
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
last_key = eliminate_unwanted_sessions(config)
|
15
|
-
while !last_key.empty?
|
16
|
-
last_key = eliminate_unwanted_sessions(config, last_key)
|
9
|
+
class << self
|
10
|
+
# Scans DynamoDB session table to find sessions that match the max age and
|
11
|
+
# max stale period requirements. it then deletes all of the found sessions.
|
12
|
+
def collect_garbage(options = {})
|
13
|
+
config = load_config(options)
|
14
|
+
last_key = eliminate_unwanted_sessions(config)
|
15
|
+
last_key = eliminate_unwanted_sessions(config, last_key) until last_key.empty?
|
17
16
|
end
|
18
|
-
end
|
19
17
|
|
20
|
-
|
21
|
-
# @option (see Configuration#initialize)
|
22
|
-
# @api private
|
23
|
-
def load_config(options = {})
|
24
|
-
Aws::SessionStore::DynamoDB::Configuration.new(options)
|
25
|
-
end
|
18
|
+
private
|
26
19
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
hash['updated_at'] = oldest_date(config.max_stale) if config.max_stale
|
33
|
-
{ :scan_filter => hash }
|
34
|
-
end
|
20
|
+
# Loads configuration options.
|
21
|
+
# @option (see Configuration#initialize)
|
22
|
+
def load_config(options = {})
|
23
|
+
Aws::SessionStore::DynamoDB::Configuration.new(options)
|
24
|
+
end
|
35
25
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
26
|
+
# Sets scan filter attributes based on attributes specified.
|
27
|
+
def scan_filter(config)
|
28
|
+
hash = {}
|
29
|
+
hash['created_at'] = oldest_date(config.max_age) if config.max_age
|
30
|
+
hash['updated_at'] = oldest_date(config.max_stale) if config.max_stale
|
31
|
+
{ scan_filter: hash }
|
32
|
+
end
|
43
33
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
config.dynamo_db_client.scan(options)
|
51
|
-
end
|
34
|
+
# Scans and deletes batch.
|
35
|
+
def eliminate_unwanted_sessions(config, last_key = nil)
|
36
|
+
scan_result = scan(config, last_key)
|
37
|
+
batch_delete(config, scan_result[:items])
|
38
|
+
scan_result[:last_evaluated_key] || {}
|
39
|
+
end
|
52
40
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end until subset.empty?
|
61
|
-
end
|
41
|
+
# Scans the table for sessions matching the max age and
|
42
|
+
# max stale time specified.
|
43
|
+
def scan(config, last_item = nil)
|
44
|
+
options = scan_opts(config)
|
45
|
+
options = options.merge(start_key(last_item)) if last_item
|
46
|
+
config.dynamo_db_client.scan(options)
|
47
|
+
end
|
62
48
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
49
|
+
# Deletes the batch gotten from the scan result.
|
50
|
+
def batch_delete(config, items)
|
51
|
+
loop do
|
52
|
+
subset = items.shift(25)
|
53
|
+
sub_batch = write(subset)
|
54
|
+
process!(config, sub_batch)
|
55
|
+
break if subset.empty?
|
56
|
+
end
|
70
57
|
end
|
71
|
-
end
|
72
58
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
response = config.dynamo_db_client.batch_write_item(opts)
|
81
|
-
opts[:request_items] = response[:unprocessed_items]
|
82
|
-
end until opts[:request_items].empty?
|
83
|
-
end
|
59
|
+
# Turns array into correct format to be passed in to
|
60
|
+
# a delete request.
|
61
|
+
def write(sub_batch)
|
62
|
+
sub_batch.each_with_object([]) do |item, rqst_array|
|
63
|
+
rqst_array << { delete_request: { key: item } }
|
64
|
+
end
|
65
|
+
end
|
84
66
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
table_opts(config).merge(scan_filter(config))
|
89
|
-
end
|
67
|
+
# Processes pending request items.
|
68
|
+
def process!(config, sub_batch)
|
69
|
+
return if sub_batch.empty?
|
90
70
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
end
|
71
|
+
opts = { request_items: { config.table_name => sub_batch } }
|
72
|
+
loop do
|
73
|
+
response = config.dynamo_db_client.batch_write_item(opts)
|
74
|
+
opts[:request_items] = response[:unprocessed_items]
|
75
|
+
break if opts[:request_items].empty?
|
76
|
+
end
|
77
|
+
end
|
99
78
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
79
|
+
# Provides scan options.
|
80
|
+
def scan_opts(config)
|
81
|
+
table_opts(config).merge(scan_filter(config))
|
82
|
+
end
|
83
|
+
|
84
|
+
# Provides table options
|
85
|
+
def table_opts(config)
|
86
|
+
{
|
87
|
+
table_name: config.table_name,
|
88
|
+
attributes_to_get: [config.table_key]
|
89
|
+
}
|
90
|
+
end
|
108
91
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
92
|
+
# Provides specified date attributes.
|
93
|
+
def oldest_date(sec)
|
94
|
+
{
|
95
|
+
attribute_value_list: [n: (Time.now - sec).to_f.to_s],
|
96
|
+
comparison_operator: 'LT'
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
# Provides start key.
|
101
|
+
def start_key(last_item)
|
102
|
+
{ exclusive_start_key: last_item }
|
103
|
+
end
|
113
104
|
end
|
114
105
|
end
|
115
106
|
end
|
@@ -1,9 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Aws::SessionStore::DynamoDB::Locking
|
2
|
-
#
|
3
|
-
# locking strategies.
|
4
|
+
# Handles session management.
|
4
5
|
class Base
|
5
|
-
|
6
|
-
# Creates configuration object.
|
6
|
+
# @param [Aws::SessionStore::DynamoDB::Configuration] cfg
|
7
7
|
def initialize(cfg)
|
8
8
|
@config = cfg
|
9
9
|
end
|
@@ -11,6 +11,7 @@ module Aws::SessionStore::DynamoDB::Locking
|
|
11
11
|
# Updates session in database
|
12
12
|
def set_session_data(env, sid, session, options = {})
|
13
13
|
return false if session.empty?
|
14
|
+
|
14
15
|
packed_session = pack_data(session)
|
15
16
|
handle_error(env) do
|
16
17
|
save_opts = update_opts(env, sid, packed_session, options)
|
@@ -19,12 +20,7 @@ module Aws::SessionStore::DynamoDB::Locking
|
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
22
|
-
#
|
23
|
-
def pack_data(data)
|
24
|
-
[Marshal.dump(data)].pack("m*")
|
25
|
-
end
|
26
|
-
|
27
|
-
# Gets session data.
|
23
|
+
# Retrieves session data based on id
|
28
24
|
def get_session_data(env, sid)
|
29
25
|
raise NotImplementedError
|
30
26
|
end
|
@@ -36,19 +32,17 @@ module Aws::SessionStore::DynamoDB::Locking
|
|
36
32
|
end
|
37
33
|
end
|
38
34
|
|
35
|
+
private
|
36
|
+
|
39
37
|
# Each database operation is placed in this rescue wrapper.
|
40
38
|
# This wrapper will call the method, rescue any exceptions and then pass
|
41
39
|
# exceptions to the configured error handler.
|
42
|
-
def handle_error(env = nil
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
@config.error_handler.handle_error(e, env)
|
47
|
-
end
|
40
|
+
def handle_error(env = nil)
|
41
|
+
yield
|
42
|
+
rescue Aws::DynamoDB::Errors::ServiceError => e
|
43
|
+
@config.error_handler.handle_error(e, env)
|
48
44
|
end
|
49
45
|
|
50
|
-
private
|
51
|
-
|
52
46
|
# @return [Hash] Options for deleting session.
|
53
47
|
def delete_opts(sid)
|
54
48
|
table_opts(sid)
|
@@ -57,11 +51,10 @@ module Aws::SessionStore::DynamoDB::Locking
|
|
57
51
|
# @return [Hash] Options for updating item in Session table.
|
58
52
|
def update_opts(env, sid, session, options = {})
|
59
53
|
if env['dynamo_db.new_session']
|
60
|
-
|
54
|
+
save_new_opts(env, sid, session)
|
61
55
|
else
|
62
|
-
|
56
|
+
save_exists_opts(env, sid, session, options)
|
63
57
|
end
|
64
|
-
updt_options
|
65
58
|
end
|
66
59
|
|
67
60
|
# @return [Hash] Options for saving a new session in database.
|
@@ -78,16 +71,21 @@ module Aws::SessionStore::DynamoDB::Locking
|
|
78
71
|
merge_all(table_opts(sid), attribute_opts)
|
79
72
|
end
|
80
73
|
|
74
|
+
# Marshal the data.
|
75
|
+
def pack_data(data)
|
76
|
+
[Marshal.dump(data)].pack('m*')
|
77
|
+
end
|
78
|
+
|
81
79
|
# Unmarshal the data.
|
82
80
|
def unpack_data(packed_data)
|
83
|
-
Marshal.load(packed_data.
|
81
|
+
Marshal.load(packed_data.unpack1('m*'))
|
84
82
|
end
|
85
83
|
|
86
84
|
# Table options for client.
|
87
85
|
def table_opts(sid)
|
88
86
|
{
|
89
|
-
:
|
90
|
-
:
|
87
|
+
table_name: @config.table_name,
|
88
|
+
key: { @config.table_key => sid }
|
91
89
|
}
|
92
90
|
end
|
93
91
|
|
@@ -102,12 +100,12 @@ module Aws::SessionStore::DynamoDB::Locking
|
|
102
100
|
|
103
101
|
# Update client with current time attribute.
|
104
102
|
def updated_at
|
105
|
-
{ :
|
103
|
+
{ value: Time.now.to_f.to_s, action: 'PUT' }
|
106
104
|
end
|
107
105
|
|
108
106
|
# Attribute for creation of session.
|
109
107
|
def created_attr
|
110
|
-
{
|
108
|
+
{ 'created_at' => updated_at }
|
111
109
|
end
|
112
110
|
|
113
111
|
# Update client with current time + max_stale.
|
@@ -124,35 +122,36 @@ module Aws::SessionStore::DynamoDB::Locking
|
|
124
122
|
# Attribute for updating session.
|
125
123
|
def updated_attr
|
126
124
|
{
|
127
|
-
|
125
|
+
'updated_at' => updated_at
|
128
126
|
}
|
129
127
|
end
|
130
128
|
|
131
129
|
def data_attr(session)
|
132
|
-
|
130
|
+
{ 'data' => { value: session, action: 'PUT' } }
|
133
131
|
end
|
134
132
|
|
135
133
|
# Determine if data has been manipulated
|
136
134
|
def data_unchanged?(env, session)
|
137
135
|
return false unless env['rack.initial_data']
|
136
|
+
|
138
137
|
env['rack.initial_data'] == session
|
139
138
|
end
|
140
139
|
|
141
140
|
# Expected attributes
|
142
141
|
def expected_attributes(sid)
|
143
|
-
{ :
|
142
|
+
{ expected: { @config.table_key => { value: sid, exists: true } } }
|
144
143
|
end
|
145
144
|
|
146
145
|
# Attributes to be retrieved via client
|
147
146
|
def attr_opts
|
148
|
-
{:
|
149
|
-
|
147
|
+
{ attributes_to_get: ['data'],
|
148
|
+
consistent_read: @config.consistent_read }
|
150
149
|
end
|
151
150
|
|
152
151
|
# @return [Hash] merged hash of all hashes passed in.
|
153
152
|
def merge_all(*hashes)
|
154
153
|
new_hash = {}
|
155
|
-
hashes.each{|hash| new_hash.merge!(hash)}
|
154
|
+
hashes.each { |hash| new_hash.merge!(hash) }
|
156
155
|
new_hash
|
157
156
|
end
|
158
157
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Aws::SessionStore::DynamoDB::Locking
|
2
4
|
# This class gets and sets sessions
|
3
5
|
# without a locking strategy.
|
@@ -18,9 +20,8 @@ module Aws::SessionStore::DynamoDB::Locking
|
|
18
20
|
|
19
21
|
# @return [String] Session data.
|
20
22
|
def extract_data(env, result = nil)
|
21
|
-
env['rack.initial_data'] = result[:item][
|
22
|
-
unpack_data(result[:item][
|
23
|
+
env['rack.initial_data'] = result[:item]['data'] if result[:item]
|
24
|
+
unpack_data(result[:item]['data']) if result[:item]
|
23
25
|
end
|
24
|
-
|
25
26
|
end
|
26
27
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Aws::SessionStore::DynamoDB::Locking
|
2
4
|
# This class implements a pessimistic locking strategy for the
|
3
5
|
# DynamoDB session handler. Sessions obtain an exclusive lock
|
@@ -19,6 +21,7 @@ module Aws::SessionStore::DynamoDB::Locking
|
|
19
21
|
private
|
20
22
|
|
21
23
|
# Get session with implemented locking strategy.
|
24
|
+
# rubocop:disable Metrics/MethodLength
|
22
25
|
def get_session_with_lock(env, sid)
|
23
26
|
expires_at = nil
|
24
27
|
result = nil
|
@@ -30,19 +33,21 @@ module Aws::SessionStore::DynamoDB::Locking
|
|
30
33
|
rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException
|
31
34
|
expires_at ||= get_expire_date(sid)
|
32
35
|
next if expires_at.nil?
|
36
|
+
|
33
37
|
result = bust_lock(sid, expires_at)
|
34
38
|
wait_to_retry(result)
|
35
39
|
end
|
36
40
|
end
|
37
41
|
get_data(env, result)
|
38
42
|
end
|
43
|
+
# rubocop:enable Metrics/MethodLength
|
39
44
|
|
40
45
|
# Determine if session has waited too long to obtain lock.
|
41
46
|
#
|
42
47
|
# @raise [Error] When time for attempting to get lock has
|
43
48
|
# been exceeded.
|
44
49
|
def exceeded_wait_time?(max_attempt_date)
|
45
|
-
lock_error = Aws::SessionStore::DynamoDB::LockWaitTimeoutError
|
50
|
+
lock_error = Aws::SessionStore::DynamoDB::Errors::LockWaitTimeoutError
|
46
51
|
raise lock_error if Time.now.to_f > max_attempt_date
|
47
52
|
end
|
48
53
|
|
@@ -54,22 +59,22 @@ module Aws::SessionStore::DynamoDB::Locking
|
|
54
59
|
# @return [Time] Time stamp for which the session was locked.
|
55
60
|
def lock_time(sid)
|
56
61
|
result = @config.dynamo_db_client.get_item(get_lock_time_opts(sid))
|
57
|
-
(result[:item][
|
62
|
+
(result[:item]['locked_at']).to_f if result[:item]['locked_at']
|
58
63
|
end
|
59
64
|
|
60
65
|
# @return [String] Session data.
|
61
66
|
def get_data(env, result)
|
62
|
-
lock_time = result[:attributes][
|
63
|
-
env[
|
64
|
-
env['rack.initial_data'] = result[:item][
|
65
|
-
unpack_data(result[:attributes][
|
67
|
+
lock_time = result[:attributes]['locked_at']
|
68
|
+
env['locked_at'] = lock_time.to_f
|
69
|
+
env['rack.initial_data'] = result[:item]['data'] if result.members.include? :item
|
70
|
+
unpack_data(result[:attributes]['data'])
|
66
71
|
end
|
67
72
|
|
68
73
|
# Attempt to bust the lock if the expiration date has expired.
|
69
74
|
def bust_lock(sid, expires_at)
|
70
|
-
|
71
|
-
|
72
|
-
|
75
|
+
return unless expires_at < Time.now.to_f
|
76
|
+
|
77
|
+
@config.dynamo_db_client.update_item(obtain_lock_opts(sid))
|
73
78
|
end
|
74
79
|
|
75
80
|
# @return [Hash] Options hash for obtaining the lock.
|
@@ -96,20 +101,20 @@ module Aws::SessionStore::DynamoDB::Locking
|
|
96
101
|
# Lock attribute - time stamp of when session was locked.
|
97
102
|
def lock_attr
|
98
103
|
{
|
99
|
-
:
|
100
|
-
:
|
104
|
+
attribute_updates: { 'locked_at' => updated_at },
|
105
|
+
return_values: 'ALL_NEW'
|
101
106
|
}
|
102
107
|
end
|
103
108
|
|
104
109
|
# Time in which session was updated.
|
105
110
|
def updated_at
|
106
|
-
{ :
|
111
|
+
{ value: Time.now.to_f.to_s, action: 'PUT' }
|
107
112
|
end
|
108
113
|
|
109
114
|
# Attributes for locking.
|
110
115
|
def add_lock_attrs(env)
|
111
116
|
{
|
112
|
-
:
|
117
|
+
add_attrs: add_attr, expect_attr: expect_lock_time(env)
|
113
118
|
}
|
114
119
|
end
|
115
120
|
|
@@ -120,25 +125,32 @@ module Aws::SessionStore::DynamoDB::Locking
|
|
120
125
|
|
121
126
|
# Lock expectation.
|
122
127
|
def lock_expect
|
123
|
-
{ :
|
128
|
+
{ expected: { 'locked_at' => { exists: false } } }
|
124
129
|
end
|
125
130
|
|
126
131
|
# Option to delete lock.
|
127
132
|
def add_attr
|
128
|
-
{
|
133
|
+
{ 'locked_at' => { action: 'DELETE' } }
|
129
134
|
end
|
130
135
|
|
131
136
|
# Expectation of when lock was set.
|
132
137
|
def expect_lock_time(env)
|
133
|
-
{
|
134
|
-
:
|
138
|
+
{
|
139
|
+
expected: {
|
140
|
+
'locked_at' => {
|
141
|
+
value: (env['locked_at']).to_s,
|
142
|
+
exists: true
|
143
|
+
}
|
144
|
+
}
|
145
|
+
}
|
135
146
|
end
|
136
147
|
|
137
148
|
# Attributes to be retrieved via client
|
138
149
|
def lock_opts
|
139
|
-
{
|
140
|
-
|
150
|
+
{
|
151
|
+
attributes_to_get: ['locked_at'],
|
152
|
+
consistent_read: @config.consistent_read
|
153
|
+
}
|
141
154
|
end
|
142
|
-
|
143
155
|
end
|
144
156
|
end
|