如何最好地调试失败的 ruby 迁移?

How to best debug a failed ruby migration?

提问人:Dan Lincoln 提问时间:11/17/2023 最后编辑:Dan Lincoln 更新时间:11/18/2023 访问量:61

问:

我的团队最近继承了一个遗留的 ruby 代码库,它有点混乱。(我自己不是 ruby 开发人员,我们团队中唯一的 ruby 开发人员已经在公司工作了 >6 个月,所以我们非常不了解我们的深度)

我们不得不添加一个 db 列,该列在开发和暂存中按预期工作,但是在部署到 prod 时,我们在启动 db:migrate rake 过程时遇到了问题(迁移和消息如下)。

暂存部署似乎使用了elastic beanstalk,其中prod部署由codedeploy直接管理到EC2实例中,因此肯定存在一些差异(我希望我们知道为什么:/ )。

任何关于从哪里开始寻找的想法将不胜感激


class AddListPriceIncVatAmountToVariants < ActiveRecord::Migration[6.0]
  def change
    add_column :variants, :list_price_inc_vat_amount, :decimal, null: false, default: 0.0

    add_index :variants, :list_price_inc_vat_amount
  end
end
** Invoke db:migrate (first_time)
** Invoke db:load_config (first_time)
** Invoke environment (first_time)
** Execute environment
rake aborted!
ArgumentError: comparison of Integer with nil failed
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/activesupport-6.0.3.6/lib/active_support/logger_thread_safe_level.rb:19:in `>='
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/activesupport-6.0.3.6/lib/active_support/logger_thread_safe_level.rb:19:in `debug?'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/newrelic_rpm-8.15.0/lib/new_relic/agent/agent_logger.rb:86:in `format_and_send'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/newrelic_rpm-8.15.0/lib/new_relic/agent/agent_logger.rb:44:in `debug'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/newrelic_rpm-8.15.0/lib/new_relic/agent/memory_logger.rb:53:in `block in dump'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/newrelic_rpm-8.15.0/lib/new_relic/agent/memory_logger.rb:52:in `each'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/newrelic_rpm-8.15.0/lib/new_relic/agent/memory_logger.rb:52:in `dump'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/newrelic_rpm-8.15.0/lib/new_relic/agent/agent_logger.rb:178:in `gather_startup_logs'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/newrelic_rpm-8.15.0/lib/new_relic/agent/agent_logger.rb:24:in `initialize'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/newrelic_rpm-8.15.0/lib/new_relic/control/private_instance_methods.rb:30:in `new'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/newrelic_rpm-8.15.0/lib/new_relic/control/private_instance_methods.rb:30:in `create_logger'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/newrelic_rpm-8.15.0/lib/new_relic/control/instance_methods.rb:58:in `init_plugin'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/newrelic_rpm-8.15.0/lib/newrelic_rpm.rb:34:in `block in <class:Railtie>'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/railties-6.0.3.6/lib/rails/initializable.rb:32:in `instance_exec'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/railties-6.0.3.6/lib/rails/initializable.rb:32:in `run'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/railties-6.0.3.6/lib/rails/initializable.rb:61:in `block in run_initializers'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:228:in `block in tsort_each'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:422:in `block (2 levels) in each_strongly_connected_component_from'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:422:in `block (2 levels) in each_strongly_connected_component_from'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:431:in `each_strongly_connected_component_from'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:421:in `block in each_strongly_connected_component_from'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/railties-6.0.3.6/lib/rails/initializable.rb:50:in `each'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/railties-6.0.3.6/lib/rails/initializable.rb:50:in `tsort_each_child'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:415:in `call'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:415:in `each_strongly_connected_component_from'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:421:in `block in each_strongly_connected_component_from'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/railties-6.0.3.6/lib/rails/initializable.rb:50:in `each'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/railties-6.0.3.6/lib/rails/initializable.rb:50:in `tsort_each_child'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:415:in `call'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:415:in `each_strongly_connected_component_from'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:349:in `block in each_strongly_connected_component'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:347:in `each'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:347:in `call'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:347:in `each_strongly_connected_component'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:226:in `tsort_each'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/tsort.rb:205:in `tsort_each'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/railties-6.0.3.6/lib/rails/initializable.rb:60:in `run_initializers'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/railties-6.0.3.6/lib/rails/application.rb:363:in `initialize!'
/home/ubuntu/platform-api/config/environment.rb:5:in `<main>'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `block in require_with_bootsnap_lfi'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require_with_bootsnap_lfi'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/zeitwerk-2.4.2/lib/zeitwerk/kernel.rb:34:in `require'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/activesupport-6.0.3.6/lib/active_support/dependencies.rb:324:in `block in require'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/activesupport-6.0.3.6/lib/active_support/dependencies.rb:291:in `load_dependency'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/activesupport-6.0.3.6/lib/active_support/dependencies.rb:324:in `require'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/railties-6.0.3.6/lib/rails/application.rb:339:in `require_environment!'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/railties-6.0.3.6/lib/rails/application.rb:523:in `block in run_tasks_blocks'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:281:in `block in execute'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:281:in `each'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:281:in `execute'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:219:in `block in invoke_with_call_chain'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/monitor.rb:235:in `mon_synchronize'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:199:in `invoke_with_call_chain'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:243:in `block in invoke_prerequisites'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:241:in `each'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:241:in `invoke_prerequisites'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:218:in `block in invoke_with_call_chain'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/monitor.rb:235:in `mon_synchronize'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:199:in `invoke_with_call_chain'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:243:in `block in invoke_prerequisites'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:241:in `each'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:241:in `invoke_prerequisites'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:218:in `block in invoke_with_call_chain'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/2.6.0/monitor.rb:235:in `mon_synchronize'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:199:in `invoke_with_call_chain'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/task.rb:188:in `invoke'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/application.rb:160:in `invoke_task'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/application.rb:116:in `block (2 levels) in top_level'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/application.rb:116:in `each'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/application.rb:116:in `block in top_level'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/application.rb:125:in `run_with_threads'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/application.rb:110:in `top_level'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/application.rb:83:in `block in run'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/application.rb:186:in `standard_exception_handling'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/lib/rake/application.rb:80:in `run'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rake-13.0.3/exe/rake:27:in `<top (required)>'
/home/ubuntu/.rbenv/versions/2.6.6/bin/rake:23:in `load'
/home/ubuntu/.rbenv/versions/2.6.6/bin/rake:23:in `<top (required)>'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.2.15/lib/bundler/cli/exec.rb:63:in `load'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.2.15/lib/bundler/cli/exec.rb:63:in `kernel_load'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.2.15/lib/bundler/cli/exec.rb:28:in `run'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.2.15/lib/bundler/cli.rb:494:in `exec'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.2.15/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.2.15/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.2.15/lib/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.2.15/lib/bundler/cli.rb:30:in `dispatch'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.2.15/lib/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.2.15/lib/bundler/cli.rb:24:in `start'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.2.15/exe/bundle:49:in `block in <top (required)>'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.2.15/lib/bundler/friendly_errors.rb:130:in `with_friendly_errors'
/home/ubuntu/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.2.15/exe/bundle:37:in `<top (required)>'
/home/ubuntu/.rbenv/versions/2.6.6/bin/bundle:23:in `load'
/home/ubuntu/.rbenv/versions/2.6.6/bin/bundle:23:in `<main>'
Tasks: TOP => db:migrate => db:load_config => environment

我们尝试过对生产数据库进行转储,并在本地运行迁移,这一切都顺利完成,因此我们非常有信心这不是数据问题。

Rails.application.configure do
  # Settings specified here will take precedence over those in config/application.rb.

  # Code is not reloaded between requests.
  config.cache_classes = true

  # Eager load code on boot. This eager loads most of Rails and
  # your application in memory, allowing both threaded web servers
  # and those relying on copy on write to perform better.
  # Rake tasks automatically ignore this option for performance.
  config.eager_load = true

  # Full error reports are disabled and caching is turned on.
  config.consider_all_requests_local = false
  config.action_controller.perform_caching = true

  # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
  # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
  # config.require_master_key = true

  # Disable serving static files from the `/public` folder by default since
  # Apache or NGINX already handles this.
  config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?

  # Enable serving of images, stylesheets, and JavaScripts from an asset server.
  # config.action_controller.asset_host = 'http://assets.example.com'

  # Specifies the header that your server uses for sending files.
  # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
  # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX

  # Store uploaded files on the local file system (see config/storage.yml for options).
  config.active_storage.service = :local

  # Mount Action Cable outside main process or domain.
  # config.action_cable.mount_path = nil
  # config.action_cable.url = 'wss://example.com/cable'
  config.action_cable.url = ENV['ACTION_CABLE_URL']
  config.action_cable.allowed_request_origins = [%r{https://*.<redacted>.com}]
  config.action_cable.disable_request_forgery_protection = true

  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
  # config.force_ssl = true

  # Use the lowest log level to ensure availability of diagnostic information
  # when problems arise.
  config.log_level = :info

  # Prepend all log lines with the following tags.
  config.log_tags = [:request_id]

  # Use a different cache store in production.
  # config.cache_store = :mem_cache_store
  config.cache_store = :redis_cache_store, {
    url: Rails.application.config_for(:redis).cache_url,
    pool_size: ENV.fetch('RAILS_MAX_THREADS', 20),
    pool_timeout: 5
  }
  config.active_record.cache_versioning = false

  # Use a real queuing backend for Active Job (and separate queues per environment).
  # config.active_job.queue_adapter     = :resque
  # config.active_job.queue_name_prefix = "app_production"

  config.action_mailer.perform_caching = false

  # Ignore bad email addresses and do not raise email delivery errors.
  # Set this to true and configure the email server for immediate delivery to raise delivery errors.
  # config.action_mailer.raise_delivery_errors = false

  # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
  # the I18n.default_locale when a translation cannot be found).
  config.i18n.fallbacks = true

  # Send deprecation notices to registered listeners.
  config.active_support.deprecation = :notify

  # Use default logging formatter so that PID and timestamp are not suppressed.
  config.log_formatter = ::Logger::Formatter.new

  # Use a different logger for distributed setups.
  # require 'syslog/logger'
  # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')

  if ENV['RAILS_LOG_TO_STDOUT'].present?
    logger = ActiveSupport::Logger.new(STDOUT)
    logger.formatter = config.log_formatter
    config.logger = ActiveSupport::TaggedLogging.new(logger)
  end

  # Do not dump schema after migrations.
  config.active_record.dump_schema_after_migration = false

  # Inserts middleware to perform automatic connection switching.
  # The `database_selector` hash is used to pass options to the DatabaseSelector
  # middleware. The `delay` is used to determine how long to wait after a write
  # to send a subsequent read to the primary.
  #
  # The `database_resolver` class is used by the middleware to determine which
  # database is appropriate to use based on the time delay.
  #
  # The `database_resolver_context` class is used by the middleware to set
  # timestamps for the last write to the primary. The resolver uses the context
  # class timestamps to determine how long to wait before reading from the
  # replica.
  #
  # By default Rails will store a last write timestamp in the session. The
  # DatabaseSelector middleware is designed as such you can define your own
  # strategy for connection switching and pass that into the middleware through
  # these configuration options.
  # config.active_record.database_selector = { delay: 2.seconds }
  # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
  # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session

  # Loggly
  # require 'syslogger'
  # config.logger = Syslogger.new("platform-api", Syslog::LOG_PID, Syslog::LOG_LOCAL7)

  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    user_name: 'apikey', # This is the string literal 'apikey', NOT the ID of your API key
    password: ENV['SENDGRID_API_KEY'], # This is the secret sendgrid API key which was issued during API key creation
    domain: '<redacted>.com',
    address: 'smtp.sendgrid.net',
    port: 587,
    authentication: :plain,
    enable_starttls_auto: true
  }

  config.middleware.use ExceptionNotification::Rack,
                        email: {
                          email_prefix: Rails.env,
                          sender_address: "'Exception Notifier' <#{ENV['SENDGRID_EMAIL']}>",
                          exception_recipients: ['carlo@<redacted>.com']
                        },
                        slack: {
                          webhook_url: ENV['SLACK_WEBHOOK'],
                          channel: '#platform-api',
                          additional_parameters: {
                            mrkdwn: true
                          }
                        }
end

Ruby-on-Rails Ruby PostgreSQL -EC2 亚马逊 elastic-beanstalk

评论


答: 暂无答案