添加新列时如何避免PG :: InFailedSqlTransaction?

时间:2017-03-24 20:56:44

标签: ruby-on-rails postgresql

我们正在针对同一个数据库运行两个rails应用程序。部署时,我们通常部署到App A,然后部署到App B,在部署期间重新启动所有rails进程。 App A在7台服务器上运行,至少有20个进程连接到数据库。 App B在4台服务器上运行,至少有8个与数据库的连接。

今天,当我们部署App A时,我们在现有表中添加了一列:

change_table :organizations do |t|
  t.integer :users_count, default: 0
end

我们预计这会很好:它在现有表上的新列并且它有一个默认值。迁移运行后不久,App A(重启之前)和App B(部署之前)出现了一些错误。

这些错误是:

FATAL ActiveRecord::StatementInvalid error: PG::InFailedSqlTransaction:
ERROR:  current transaction is aborted, commands ignored until end of 
transaction block

在postgres日志中,我有58个这样的错误:

postgres[12283]: ERROR:  cached plan must not change result type
postgres[12283]: STATEMENT:  SELECT  "organizations".* FROM 
  "organizations" WHERE "organizations"."id" = $1 LIMIT $2

这会重复多次,并在所有部署完成并重新启动所有进程后消失。

似乎Rails bug #12330Rails PR 22170在Rails 5.0中解决了这个问题,但是我已经提交了这个错误。

相关软件版本

  • Rails 5.0.2
  • PG 0.19.0
  • Postgres 9.5

Rails bug #12330的一条评论表明我必须添加null默认值的列。另一个建议执行多个部署,一个用于禁用prepare语句,另一个用于执行迁移并重新启用预准备语句。

有没有避免这种情况?当我们重新启动服务器时它会清除,但我觉得我错过了一些东西 - 比如只使用可空列可能会一起避免这些错误。这不会发生在每次部署中,我不知道如何重现它 - 但这不是第一次发生。

1 个答案:

答案 0 :(得分:0)

您已更改了表结构,因此更改了准备好的SELECT返回的内容,因为您使用"organizations".*,并返回所有列。 PostgreSQL显然不支持更新预准备语句,因此您需要创建新会话(重新连接)或使用DEALLOCATE删除该预准备语句。

编辑:您也可以停止使用SELECT *