aws / aws-sdk-ruby-record

Official repository for the aws-record gem, an abstraction for Amazon DynamoDB.
Apache License 2.0
318 stars 41 forks source link

rake aws_record:migrate broken with two table configs on the same model #143

Open thomaswitt opened 1 week ago

thomaswitt commented 1 week ago

When creating two global secondary indexes for the same model, this leads to the following error message:

$ rake aws_record:migrate
running db/table_config/gsi_user_login.rb
running db/table_config/user_email_gsi.rb
Aws::DynamoDB::Errors::LimitExceededException: Subscriber limit exceeded: Only 1 online index can be created or deleted simultaneously per table (Aws::DynamoDB::Errors::LimitExceededException)

It gets especially weird: When I uncomment one global_secondary_index from the user model, rake aws_record:migrate runs just fine (so it's not the db/table_config files). When I then Re-Insert the global_secondary_index in the user model and run rake aws_record:migrate again, all indexes are created correctly.

So the gem can't correctly handle if two global_secondary_indexes are defined in the same model and the migrations will be run after each other.

class User
  include Aws::Record

  string_attr :user_email
  string_attr :user_login

  global_secondary_index(:user_email_gsi,
                         hash_key: :user_email,
                         projection: { projection_type: 'ALL' })

  global_secondary_index(:user_login_gsi,
                         hash_key: :user_login,
                         projection: { projection_type: 'ALL' })

end

db/table_config/gsi_user_login.rb

require "aws-record"

module ModelTableConfig
  def self.config
    Aws::Record::TableConfig.define do |t|
      t.model_class User
      t.billing_mode "PAY_PER_REQUEST"
      t.global_secondary_index(:user_login_gsi)
    end
  end
end

db/table_config/user_email_gsi.rb

require "aws-record"

module ModelTableConfig
  def self.config
    Aws::Record::TableConfig.define do |t|
      t.model_class User
      t.billing_mode "PAY_PER_REQUEST"
      t.global_secondary_index(:user_email_gsi)
    end
  end
end
mullermp commented 1 week ago

Thanks for opening an issue. The error you encountered is a service side error - it looks like you are modifying the same table at the same time. I actually think you only need one migration here. t.global_secondary_index appends to a hash before execution. Try just a single migration:

module ModelTableConfig
  def self.config
    Aws::Record::TableConfig.define do |t|
      t.model_class User
      t.billing_mode "PAY_PER_REQUEST"
      t.global_secondary_index(:user_email_gsi)
      t.global_secondary_index(:user_login_gsi) 
    end
  end
end

https://github.com/aws/aws-sdk-ruby-record/blob/df9a582065d49187fbc0851df1d31d8f3e8504ca/lib/aws-record/record/table_config.rb#L177-L181