個人用Misskeyでドライブにファイルをアップロードした際に次のようなエラーが起きるようになりました。これを調査・エラーが起こらないように対策した記録です
この記事が想定する読者
- Misskeyインスタンスを運用している
- PostgreSQLのレプリケーションを行っており、MisskeyがReadリクエストをレプリカの側に送るように設定している
- ドライブへのアップロード時に上のようなエラーが起きるようになった
解決策
postgresqlのレプリケーションを非同期から同期で行われるように変更する
概要
ここで書いたような設定でMisskeyをしばらく運用していました。ある時MisskeyのDBでレプリケーションを有効にした後、次のようなエラーが起きるようになりました
このようにアップロード失敗と表示されていますが、実際には正しくアップロードされており、ページを更新することで表示されるようになります
原因
misskeyやredisの再起動などを試しましたが、解決しなかったため2週間ほど放置していました。
先日やる気が出たのでログを調査したところ次のようなエラーが出ていました
またソースコードを確認したところ前述のエラーコードはハンドリングされなかった際に起こるエラーであるようでした(そこまでしっかり見てないので違うかもしれません)
またEntityNotFoundError
はTypeORMに関連したエラーであるため、DBに想定されていたレコードがないことが原因だということもわかりました
ここまでで以下のような仮説を考えました
- ドライブにアップロードすると、ハッシュ値か何かを含んだレコードがDBに作成される。またジョブキューにも追加される
- ジョブキューの中身を見て、Read読み込みがレプリカDBに行く
- レプリケーションがまだ終わっていない場合、当然そのレコードは存在しない
- TypeORMが
EntityNotFoundError
を発生させ、どこにもハンドリングされないままApiError
が送出される - 完了しなかったジョブキューが再度実行される。このタイミングではレプリケーションが完了し正常に動作する
- ドライブにファイルがアップロードされる
対策実行
まず仮説が正しいかどうか検証を行いました。上記の仮説のポイントはReadとWriteを行っているDBにおいてレプリケーションが行われていることです。そこでMisskeyでレプリケーションを無効にしてから、上記の現象が発生するか確かめたところエラーは起きないようになりました
ある程度正しそうなことが分かったので、レプリケーションを有効にしながらできる対策を考えます。問題はDBのプライマリにWriteされたことがレプリカ側にすぐ反映されていないことなので、レプリケーションの設定を非同期から同期に変更しました。今回の環境ではcloudnative-pgを使って構成していたので設定変更は非常に簡単で、次の設定をマニフェストに加えるだけでした
https://cloudnative-pg.io/documentation/1.22/replication/#synchronous-replication
この状態で再度Misskeyの設定を有効に変更するとエラーが起きずにアップロードできることを確認できました
終わりに
実はレプリケーションを有効にしたタイミングでMisskeyのバージョンを上げる作業も行っていたので、当初はこのバージョンアップが原因だと思い、むだな時間を使ってしまいました。 蓋を開けてみれば簡単でしたね…