axiosライブラリにリトライパラメータを追加して、柔軟なリトライ処理を行う方法について紹介します。以前、Repository Factoryパターンを紹介した際に利用したプラグインの知識を利用して行います。

やりたいこと

リトライ処理を組む上で、考えることを下記に示します。

  • リトライ回数を指定したい。
  • リトライする際の間隔を指定したい。
  • リトライ処理は、共通化したい。

共通化処理

Axiosライブラリの拡張機能を利用します。エラーハンドリングを受け付けるonErrorを利用します。こちらの内容は、axios公式のextendで紹介されている方法です。nuxt.jsでは、axiosインスタンスがコンテキストにインジェクションされていますので、そのaxiosインスタンスを拡張します。pluginの初期化時にcontextを受け取ることができるので、そのコンテキストから$axiosインスタンスを取得し、そのインスタンスを拡張します。それでは、ソースコードを示します。

// ~/plugin/axios.ts
import { AxiosError } from 'axios'
import { defineNuxtPlugin } from '@nuxtjs/composition-api'

export default defineNuxtPlugin((ctx) => {
  const { $axios, error } = ctx
  $axios.onError((err: AxiosError) => {
    if (!err.response) {
      // エラーレスポンスがない、net::ERR_CONNECTION_REFUSEDなどは、ここで処理する
      error({ statusCode: 500, message: 'システムがダウンしています。時間をおいてやり直してください。' })
      return
    }

    // リトライしてもだめなエラーはここで処理しておく

    const axiosErr = err as AxiosError
    if (!('retryMax' in axiosErr.config)) {
      // リトライ対象でない場合
      return Promise.reject(err)
    }

    // リトライカウントを設定する
    const retryCount = ('retryCount' in axiosErr.config) ?  (axiosErr.config as any).retryCount + 1: 1
    const retryMax = (axiosErr.config as any).retryMax
    if (retryCount > retryMax) {
      return Promise.reject(err)
    }

    const waitTime = (axiosErr.config as any).retryDelayMillsec || 1
    const nextTry = new Promise((resolve) => {
      setTimeout(() => {
        resolve()
      }, waitTime)
    })

    // リトライを実行する
    return nextTry.then(() => {
      return $axios.request({
        ...( axiosErr.config as any),
        ...{ retryCount: retryCount },
      })
    })
  })
})

エラーハンドリング処理では、共通で処理したいエラーを処理します。

  1. エラー応答がない場合の処理
  2. リトライが不要なエラーのハンドリング
  3. リトライするための情報があるかどうかを見て、その情報にそったリトライを行う。上限設定を設けて、無限ループにならないようにする。

利用するコードを示します。

// リトライを使わないコード
const res = await $axios.$get(reqUrl)

// リトライをする場合(リトライ回数上限、リトライ処理の待ち時間msec)
const res = await $axios.$get(reqUrl, {
  retryMax: 2,
  retryDelayMillsec: 5,
})

まとめ

今回は、axiosの拡張機能を使って、リトライ機能の実装を紹介しました。axisoの各メソッドでは、configを渡すでこのconfigを実行時のコンテキストとして利用することができました。リクエスト時の処理共通化や、OAuth2.0系に沿ったAPIのリフレッシュトークンのトークンの更新処理など他にも利用方法がありそうですね。お疲れ様でした。