開発環境である時見慣れぬエラーが出て、もしも本番で発生したらどうすればいいのか途方に暮れそうなので、復旧手順を試行錯誤したメモです。同じエラーが出た場合にヒントになればと思うのですが、同じ状況とは限らないのでご注意。
環境 rails 5.2.4.3 postgresql 12.2 pg 1.2.2 activerecord-session_store 1.1.3
状況
ログインするサイトで、ブラウザからアクセスした際に以下のエラーが出て、サイトをまったく利用できない。
ActiveRecord::StatementInvalid (PG::SyntaxError: ERROR: zero-length delimited identifier at or near """"
LINE 1: ... SET "data" = $1, "updated_at" = $2 WHERE "sessions"."" = $3
: UPDATE "sessions" SET "data" = $1, "updated_at" = $2 WHERE "sessions"."" = $3)
:
activerecord (5.2.4.3) lib/active_record/connection_adapters/postgresql_adapter.rb:611:in `exec_params'
activerecord (5.2.4.3) lib/active_record/connection_adapters/postgresql_adapter.rb:611:in `block (2 levels) in exec_no_cache'
...
ログに羅列されているファイル名には自分が書いたファイルはなく心当たりなし。昨日何やったっけ。とりあえずこの状態のDBをダンプして保存。
セッションの情報はactiverecord-session_storeでactiverecordに記録していて、ユーザがアクセスするとこの情報を更新する。その際にこのエラーが出ている。
正常に動いている本番データと比べると、whereのところは本来は
WHERE "sessions"."id" = $3 のはずであることがわかった。
activerecord-5.2.4.3/lib/active_record/connection_adapters/abstract/database_statements.rb
までは追っかけて、発行するsqlを生成する関数の入力値arelでname="id"であるところが、エラーが出るパターンではname=""になっていたところまではわかったが、そこから遡るのは断念。
pg_dumpしてpsqlでloadしても同じエラー。そこで、pg_dumpをデータだけにして、dbは一度初期化、migrateしてデータを流し込んだら復旧できた。復旧後改めてpg_dumpして比較すると、
ALTER TABLE ONLY public.sessions
ADD CONSTRAINT sessions_pkey PRIMARY KEY (id);
が欠けていた。どこで/何をしてこれが消えたのか、心当たりなし。
sessionsのテーブルだけであれば、邪道っぽいけど、以下のようにactiverecord-session_store適用でやったのと同じmigrationを一時的に用意し、
class ResetSessionTable < ActiveRecord::Migration[5.2]
def up
drop_table :sessions
create_table :sessions do |t|
t.string :session_id, :null => false
t.text :data
t.timestamps
end
add_index :sessions, :session_id, :unique => true
add_index :sessions, :updated_at
end
def down
end
end
# pg_dump -b DB名 --data-only --table sessions >sessions_bak.sql
# ここで上記をdb:migrateしてすぐにdb:rollbackしてファイルを削除
# cat sessions_bak.sql |/usr/local/pgsql/bin/psql -e DB名
こんな感じで停止もそこそこで復旧できる見通しはついた。もっと良い対応があるかもしれない。
結局発生の原因はわかっていないが、開発環境は初期化とかデータロードを頻繁に行っているため、そこで何らかエラーがあった可能性が高いけど、pgのバージョンの制約とか、他のgemとかの影響の可能性もなくはないので、情報共有で投稿してみました。