MyXQLやPostgrexのドキュメントを読めば書いてあるのですが、結構調査に時間がかかったのでメモ。
MySQLの場合はdisconnect_on_error_codes: [:ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION]
、また、PostgreSQLの場合はdisconnect_on_error_codes: [:read_only_sql_transaction]
を足せばOKです。
MySQLの例
config :my_app, Repo,
database: "ecto_simple",
username: "user",
password: "pass",
hostname: "localhost",
disconnect_on_error_codes: [:ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION]
備考: Auroraのフェイルオーバー問題とは
AWSのAuroraはMultiAZでフェイルオーバーすると、ReaderとWriterのノードが入れ替わります。このときEctoのようなコネクションをプールするDB接続ライブラリでは、Writerのつもりで入れ替わったReaderに書き込みリクエストを送り、エラーになるという現象が起きます。
このように読み取り専用DBに書き込みリクエストを送ったエラーが出たときに、DB接続ライブラリがプールしていたコネクションを破棄して再接続してくれれば、システム全体としては自動復旧します。逆に破棄してくれないとすると、故障した状態が維持されてしまい、最悪手動で再起動が必要な事態になってしまいます。
ただ、"読み取り専用DBに書き込みリクエストを送ったエラーが出たときに、DB接続ライブラリがプールしていたコネクションを破棄して再接続"はAuroraでは必須でほしい挙動ですが、Aurora以外のMySQL/PosgreSQLを使っている場合は逆に意味不明な挙動です。よってEctoではオプショナルなのだと思います。他のDB接続ライブラリだと、例えばActiveRecord (Rails)では設定オプションで有効にもできないので、自分でモンキーパッチをあてて解決する方法が有名だったりします。
参考
- Ecto.Repo — Ecto v3.8.4
- MyXQLのドキュメントに書いてあるdisconnect_on_error_codesの説明
- Posgrexのオプション
- 関連PR