チャンク分割バックアップアップローダーがDiscourseのリクエストレート制限を超過

ある顧客が、管理UIからローカルのDiscourseバックアップをアップロードする際に、再現可能な問題に遭遇しました。

バックアップアップローダーは固定の5 MBチャンクを使用しており、十分に高速な接続環境では、Discourse自体のアプリケーションレベルのリクエストレート制限を超えるほどのリクエストを生成する可能性があります。その場合、サーバーはHTTP 429を返しますが、チャンクアップローダーは429レスポンスのリトライを行わず、Retry-Afterヘッダーも尊重しません。その結果、バックアップのアップロード全体が失敗します。

非2xxレスポンスはエラーに変換されます:

if (ev.target.status < 200 || ev.target.status >= 300) {
  const error = new Error("Non 2xx");
  error.source = ev.target;
  reject(error);
  return;
}

リトライロジックは以下の通りです:

_shouldRetry(err) {
  if (err.source && typeof err.source.status === "number") {
    const { status } = err.source;

    return (
      status === 0 ||
      status === 409 ||
      status === 423 ||
      (status >= 500 && status < 600)
    );
  }

  return false;
}

したがって、HTTP 429は明示的にリトライ可能ではありません。

429レスポンスが1回あるだけで、チャンクアップロードのプロミスが失敗し、最終的にバックアップアップロード全体でupload-errorがトリガーされます。

また、Retry-Afterレスポンスヘッダーの処理もありません。


2021年のこのトピックを見つけましたが、かなり早く話題が逸れました。しかし、おそらくまったく同じ問題と思われます。