class Aws::SessionStore::DynamoDB::Locking::Pessimistic
This class implements a pessimistic locking strategy for the DynamoDB
session handler. Sessions obtain an exclusive lock for reads that is only released when the session is saved.
Public Instance Methods
Gets session from database and places a lock on the session while you are reading from the database.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 15 def get_session_data(env, sid) handle_error(env) do get_session_with_lock(env, sid) end end
Saves the session.
Aws::SessionStore::DynamoDB::Locking::Base#set_session_data
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 9 def set_session_data(env, sid, session, options = {}) super(env, sid, session, set_lock_options(env, options)) end
Private Instance Methods
Option to delete lock.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 132 def add_attr { 'locked_at' => { action: 'DELETE' } } end
Attributes for locking.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 115 def add_lock_attrs(env) { add_attrs: add_attr, expect_attr: expect_lock_time(env) } end
Attempt to place a lock on the session.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 97 def attempt_set_lock(sid) @config.dynamo_db_client.update_item(obtain_lock_opts(sid, lock_expect)) end
Attempt to bust the lock if the expiration date has expired.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 74 def bust_lock(sid, expires_at) return unless expires_at < Time.now.to_f @config.dynamo_db_client.update_item(obtain_lock_opts(sid)) end
Determine if session has waited too long to obtain lock.
@raise [Error] When time for attempting to get lock has
been exceeded.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 49 def exceeded_wait_time?(max_attempt_date) lock_error = Aws::SessionStore::DynamoDB::Errors::LockWaitTimeoutError raise lock_error if Time.now.to_f > max_attempt_date end
Expectation of when lock was set.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 137 def expect_lock_time(env) { expected: { 'locked_at' => { value: (env['locked_at']).to_s, exists: true } } } end
@return [String] Session data.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 66 def get_data(env, result) lock_time = result[:attributes]['locked_at'] env['locked_at'] = lock_time.to_f env['rack.initial_data'] = result[:item]['data'] if result.members.include? :item unpack_data(result[:attributes]['data']) end
Get the expiration date for the session
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 91 def get_expire_date(sid) lock_date = lock_time(sid) lock_date + (0.001 * @config.lock_expiry_time) if lock_date end
@return [Hash] Options hash for placing a lock on a session.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 55 def get_lock_time_opts(sid) merge_all(table_opts(sid), lock_opts) end
Get session with implemented locking strategy. rubocop:disable Metrics/MethodLength
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 25 def get_session_with_lock(env, sid) expires_at = nil result = nil max_attempt_date = Time.now.to_f + @config.lock_max_wait_time while result.nil? exceeded_wait_time?(max_attempt_date) begin result = attempt_set_lock(sid) rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException expires_at ||= get_expire_date(sid) next if expires_at.nil? result = bust_lock(sid, expires_at) wait_to_retry(result) end end get_data(env, result) end
Lock attribute - time stamp of when session was locked.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 102 def lock_attr { attribute_updates: { 'locked_at' => updated_at }, return_values: 'ALL_NEW' } end
Lock expectation.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 127 def lock_expect { expected: { 'locked_at' => { exists: false } } } end
Attributes to be retrieved via client
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 149 def lock_opts { attributes_to_get: ['locked_at'], consistent_read: @config.consistent_read } end
@return [Time] Time stamp for which the session was locked.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 60 def lock_time(sid) result = @config.dynamo_db_client.get_item(get_lock_time_opts(sid)) (result[:item]['locked_at']).to_f if result[:item]['locked_at'] end
@return [Hash] Options hash for obtaining the lock.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 81 def obtain_lock_opts(sid, add_opt = {}) merge_all(table_opts(sid), lock_attr, add_opt) end
Lock options for setting lock.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 122 def set_lock_options(env, options = {}) merge_all(options, add_lock_attrs(env)) end
Time in which session was updated.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 110 def updated_at { value: Time.now.to_f.to_s, action: 'PUT' } end
Sleep for given time period if the session is currently locked.
# File lib/aws/session_store/dynamo_db/locking/pessimistic.rb, line 86 def wait_to_retry(result) sleep(0.001 * @config.lock_retry_delay) if result.nil? end