Spaces:
Sleeping
Sleeping
| import { AppError, URLInputErrorType } from './errors'; | |
| // リトライ可能なエラーかどうか判定 | |
| export function isRetryableError(error: unknown): boolean { | |
| if (error instanceof AppError) { | |
| return [ | |
| URLInputErrorType.NETWORK_ERROR, | |
| URLInputErrorType.TIMEOUT, | |
| ].includes(error.code as URLInputErrorType); | |
| } | |
| return false; | |
| } | |
| // エラーの詳細情報を取得 | |
| export function getErrorDetails(error: unknown): { | |
| message: string; | |
| code?: string; | |
| statusCode?: number; | |
| isRetryable: boolean; | |
| } { | |
| if (error instanceof AppError) { | |
| return { | |
| message: error.message, | |
| code: error.code, | |
| statusCode: error.statusCode, | |
| isRetryable: isRetryableError(error), | |
| }; | |
| } | |
| if (error instanceof Error) { | |
| return { | |
| message: error.message, | |
| isRetryable: false, | |
| }; | |
| } | |
| return { | |
| message: '予期しないエラーが発生しました', | |
| isRetryable: false, | |
| }; | |
| } | |
| // 指数バックオフでリトライ | |
| export async function retryWithBackoff<T>( | |
| fn: () => Promise<T>, | |
| maxRetries: number = 3, | |
| initialDelay: number = 1000, | |
| ): Promise<T> { | |
| let lastError: unknown; | |
| for (let i = 0; i < maxRetries; i++) { | |
| try { | |
| return await fn(); | |
| } catch (error) { | |
| lastError = error; | |
| // リトライ不可能なエラーの場合は即座に失敗 | |
| if (!isRetryableError(error)) { | |
| throw error; | |
| } | |
| // 最後の試行の場合はエラーを投げる | |
| if (i === maxRetries - 1) { | |
| throw error; | |
| } | |
| // 指数バックオフで待機 | |
| const delay = initialDelay * Math.pow(2, i); | |
| await new Promise((resolve) => setTimeout(resolve, delay)); | |
| } | |
| } | |
| throw lastError; | |
| } | |