module Dynamo::Record::BatchGet::ClassMethods

Public Instance Methods

batch_get(keys) click to toggle source
# File lib/dynamo/record/batch_get.rb, line 11
def batch_get(keys)
  process_batch_get_requests(keys)
end

Private Instance Methods

build_item_from_hash(resp) click to toggle source

Convert response hashes to Record instances Adapted from `build_item_from_resp` used by `find` but that method is closely tied to get_item response format github.com/aws/aws-sdk-ruby-record/blob/v2.3.0/lib/aws-record/record/item_operations.rb#L593

# File lib/dynamo/record/batch_get.rb, line 63
def build_item_from_hash(resp)
  record = new
  data = record.instance_variable_get('@data')
  attributes.attributes.each do |name, attr|
    data.set_attribute(name, attr.extract(resp))
    data.new_record = false
  end
  record
end
get_batch_from_dynamo(batch) click to toggle source

BatchGetItem will return a partial result if provisioned throughput is exceeded or an internal error occurs. If all items cannot be processed ProvisionedThroughputExceededException is raised. docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html#batch_get_item-instance_method

# File lib/dynamo/record/batch_get.rb, line 46
def get_batch_from_dynamo(batch)
  response = dynamodb_client.batch_get_item(
    request_items: {
      table_name => { keys: batch }
    }
  )
  [
    response.responses[table_name],
    response.unprocessed_keys[table_name]&.keys || []
  ]
rescue Aws::DynamoDB::Errors::ProvisionedThroughputExceededException
  [[], batch]
end
process_batch_get_requests(keys) click to toggle source
# File lib/dynamo/record/batch_get.rb, line 17
def process_batch_get_requests(keys) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
  attempt = 1
  results = []
  unprocessed_keys = keys.dup.map(&:stringify_keys)
  while !unprocessed_keys.empty? && attempt <= max_retries
    batch = unprocessed_keys.shift(BATCH_SIZE)
    Dynamo::Record.logger.debug "#{name} batch_get_item #{batch.count} request_items"
    processed, unprocessed = get_batch_from_dynamo(batch)
    results.concat(processed)

    next if unprocessed.empty?

    Dynamo::Record.logger.debug "#{name} batch_get_item #{unprocessed.count} unprocessed_keys"
    unprocessed_keys.unshift(*unprocessed)
    sleep(rand(1 << attempt) + 1)
    attempt += 1
  end

  if !unprocessed_keys.empty? && attempt > max_retries
    raise NumberOfRetriesExceeded.new(keys), 'Number of retries exceeded'
  end

  results.map { |r| build_item_from_hash(r) }
end