将rails app部署到heroku时,定期看到PG :: InFailedSqlTransaction错误

时间:2016-05-13 19:11:08

标签: postgresql ruby-on-rails-4 heroku

每当我们部署Rails / Postgres应用程序并且迁移是部署的一部分时,我们会收到以下错误:

  

PG :: InFailedSqlTransaction:错误:当前事务被中止,   命令被忽略,直到事务块结束

     

PG :: FeatureNotSupported:错误:缓存计划不得更改结果   型

违规的SQL事务通常是不同的。

我想知道在部署时是否有办法防止这种情况发生?

1 个答案:

答案 0 :(得分:0)

原因:

准备好的陈述经过兑现以提高绩效。 每当在涉及的表的模式发生更改后使用预准备语句时,您将获得:

PG::FeatureNotSupported: ERROR: cached plan must not change result type

PG的适配器通常通过优雅地DEALLOCATE准备好的声明来恢复。

但是,如果事务中发生错误,则事务已经失败。 DEALLOCATE语句在同一事务中运行,因此将回滚。 所以连接留下了一个不起作用的兑现准备语句。

解决方案:

  • 升级到Rails 5.0.4+,问题已解决there
  • 运行迁移时,没有任何rails进程正在运行。如果您希望零停机时间部署,则不适用。如果您有多个应用程序访问相同的数据库,则适用但不方便。
  • 完全
  • Disable prepared statements。可能会或可能不会导致性能下降:

    # config/database.yml
    
    production:
      prepared_statements: false
    
  • following monkey patch添加到ActiveRecord::Base(稍加修改的版本):

    # config/initializers/rails_recoverable_transactions.rb
    
    raise "Remove monkey patch in #{__FILE__}" if Rails::VERSION::MAJOR > 4
    
    module TransactionRecoverable
      module ClassMethods
        def transaction(*args)
          super(*args) do
            yield
          end
        rescue PG::InFailedSqlTransaction
          connection.rollback_db_transaction
          connection.clear_cache!
    
          super(*args) do
            yield
          end
        end
      end
    end
    
    class << ActiveRecord::Base
      prepend TransactionRecoverable::ClassMethods
    end
    

这可以确保如果在事务中出现错误,则先关闭事务,然后清除缓存,然后重试事务一次。如果由于某种原因您不想重试交易,可以删除super块内的rescue来电。