Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Aws::DynamoDB::Client describe_table returning nil with VCR #270

Closed
kdiogenes opened this issue Jun 18, 2018 · 5 comments
Closed

Aws::DynamoDB::Client describe_table returning nil with VCR #270

kdiogenes opened this issue Jun 18, 2018 · 5 comments

Comments

@kdiogenes
Copy link

While using Dynamoid with VCR I started to perceive random failures on my tests. I can't identify the root of the problem, but I think it's something related with Aws::DynamoDB::Client describe_table method.

This is the the stacktrace of the error during the test execution:

     NoMethodError:
       undefined method `[]' for nil:NilClass
     # /home/kadu/.rvm/gems/ruby-2.5.1@kceprb/gems/dynamoid-2.2.0/lib/dynamoid/adapter_plugin/aws_sdk_v2.rb:1003:in `hash_key'
     # /home/kadu/.rvm/gems/ruby-2.5.1@kceprb/gems/dynamoid-2.2.0/lib/dynamoid/adapter_plugin/aws_sdk_v2.rb:771:in `key_stanza'
     # /home/kadu/.rvm/gems/ruby-2.5.1@kceprb/gems/dynamoid-2.2.0/lib/dynamoid/adapter_plugin/aws_sdk_v2.rb:429:in `get_item'
     # /home/kadu/.rvm/gems/ruby-2.5.1@kceprb/gems/dynamoid-2.2.0/lib/dynamoid/adapter.rb:151:in `block (3 levels) in <class:Adapter>'
     # /home/kadu/.rvm/gems/ruby-2.5.1@kceprb/gems/dynamoid-2.2.0/lib/dynamoid/adapter.rb:53:in `benchmark'
     # /home/kadu/.rvm/gems/ruby-2.5.1@kceprb/gems/dynamoid-2.2.0/lib/dynamoid/adapter.rb:151:in `block (2 levels) in <class:Adapter>'
     # /home/kadu/.rvm/gems/ruby-2.5.1@kceprb/gems/dynamoid-2.2.0/lib/dynamoid/adapter.rb:91:in `read'
     # /home/kadu/.rvm/gems/ruby-2.5.1@kceprb/gems/dynamoid-2.2.0/lib/dynamoid/finders.rb:100:in `find_by_id'
     # /home/kadu/.rvm/gems/ruby-2.5.1@kceprb/gems/dynamoid-2.2.0/lib/dynamoid/identity_map.rb:31:in `find_by_id'
     # /home/kadu/.rvm/gems/ruby-2.5.1@kceprb/gems/dynamoid-2.2.0/lib/dynamoid/document.rb:118:in `exists?'

The problem in this method is that schema is nil, this is the content of the hash_key method:

@hash_key ||= schema[:key_schema].find { |d| d[:key_type] == HASH_KEY  }.try(:attribute_name).to_sym

I put a breakpoint in dynamoid-2.2.0/lib/dynamoid/adapter_plugin/aws_sdk_v2.rb @ line 804 Dynamoid::AdapterPlugin::AwsSdkV2#describe_table: and this is the output of some calls I have made manually:

    801: def describe_table(table_name, reload = false)
    802:   (!reload && table_cache[table_name]) || begin
    803:     binding.pry
 => 804:     table_cache[table_name] = Table.new(client.describe_table(table_name: table_name).data)
    805:   end
    806: end

[1] pry(#<Dynamoid::AdapterPlugin::AwsSdkV2>)> client.describe_table(table_name: table_name).data
=> #<struct Aws::DynamoDB::Types::DescribeTableOutput table=nil>
[2] pry(#<Dynamoid::AdapterPlugin::AwsSdkV2>)> table_name
=> "ceps-prod"
[3] pry(#<Dynamoid::AdapterPlugin::AwsSdkV2>)> client.describe_table(table_name: table_name).data
=> #<struct Aws::DynamoDB::Types::DescribeTableOutput table=nil>
[4] pry(#<Dynamoid::AdapterPlugin::AwsSdkV2>)> client.describe_table(table_name: table_name).data
=> #<struct Aws::DynamoDB::Types::DescribeTableOutput table=nil>
[5] pry(#<Dynamoid::AdapterPlugin::AwsSdkV2>)> client.describe_table(table_name: table_name).data
=> #<struct Aws::DynamoDB::Types::DescribeTableOutput
 table=
  #<struct Aws::DynamoDB::Types::TableDescription
   attribute_definitions=[#<struct Aws::DynamoDB::Types::AttributeDefinition attribute_name="cep", attribute_type="N">],
   table_name="ceps-prod",
   key_schema=[#<struct Aws::DynamoDB::Types::KeySchemaElement attribute_name="cep", key_type="HASH">],
   table_status="ACTIVE",
   creation_date_time=2018-06-18 00:48:01 -0300,
   provisioned_throughput=
    #<struct Aws::DynamoDB::Types::ProvisionedThroughputDescription
     last_increase_date_time=1969-12-31 21:00:00 -0300,
     last_decrease_date_time=1969-12-31 21:00:00 -0300,
     number_of_decreases_today=0,
     read_capacity_units=100,
     write_capacity_units=20>,
   table_size_bytes=256,
   item_count=2,
   table_arn="arn:aws:dynamodb:ddblocal:000000000000:table/ceps-prod",
   table_id=nil,
   local_secondary_indexes=nil,
   global_secondary_indexes=nil,
   stream_specification=nil,
   latest_stream_label=nil,
   latest_stream_arn=nil,
   restore_summary=nil,
   sse_description=nil>>

I'm using a local dynamodb with the dynamodb-local gem. I also used a dynamodb in AWS and have the same error.

Appreciate any help with this issue, thanks!

@andrykonchin
Copy link
Member

I may guess the table isn't created yet.

Table creation is asynchronous operation in DynamoDB. So there is a very small possibility the slow dynamodb-local causes the issue.

You can check it by passing sync: true option to<Document>.create_table method call before tests running. There are several config options you may need to play with - sync_retry_wait_seconds and sync_retry_max_times.

Default values are:

config.sync_retry_wait_seconds = 0
config.sync_retry_max_times = 3

@kdiogenes
Copy link
Author

I put the following in my DynamoidReset module, as pointed by https://www.rubydoc.info/gems/dynamoid/2.2.0#Test_Environment:

Dynamoid.included_models.each do |model|
  begin
    model.create_table(sync: true)
  rescue
    retry
  end
end

Still getting the same error.

@kdiogenes
Copy link
Author

I configured VCR to ignore all request to localhost and also configured dynamoid with:

module DynamoidTruncate
  def self.all
    if Dynamoid.adapter.list_tables
      Dynamoid.adapter.list_tables.each do |table|
        if table =~ /^#{Dynamoid::Config.namespace}/
          Dynamoid.adapter.truncate(table)
        end
      end
    end
    Dynamoid.included_models.each(&:create_table)
  end
end

RSpec.configure do |config|
  config.before(:suite) do
    Dynamoid.included_models.each do |model|
      begin
        model.create_table(sync: true)
      rescue
        retry
      end
    end
  end

  config.before(:each) do
    DynamoidTruncate.all
  end
end

It's working know 🎉

@andrykonchin
Copy link
Member

Actually it makes sense to create table synchronously as well here in DynamoidTruncate.all:

Dynamoid.included_models.each(&:create_table)

@kdiogenes
Copy link
Author

I decided to not drop my tables, only truncate it. I run RAILS_ENV=test bundle exec rake dynamoid:create_tables in my CI to create the tables before the tests run. It's working awesome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants