/** * JST (Asia/Tokyo) タイムゾーンでISO 8601形式のタイムスタンプを生成 */ function getJSTTimestamp(): string { const now = new Date(); // JSTタイムゾーンで時刻を取得してISO形式に変換 return new Date(now.toLocaleString('en-US', { timeZone: 'Asia/Tokyo' })).toISOString(); } export enum SegmentationErrorCode { INITIALIZATION_FAILED = 'INITIALIZATION_FAILED', MODEL_NOT_INITIALIZED = 'MODEL_NOT_INITIALIZED', INVALID_IMAGE_DATA = 'INVALID_IMAGE_DATA', SEGMENTATION_FAILED = 'SEGMENTATION_FAILED', MASK_GENERATION_FAILED = 'MASK_GENERATION_FAILED', INVALID_MASK_DATA = 'INVALID_MASK_DATA', MEMORY_LIMIT_EXCEEDED = 'MEMORY_LIMIT_EXCEEDED', PROCESSING_TIMEOUT = 'PROCESSING_TIMEOUT', BACKGROUND_INPAINTING_FAILED = 'BACKGROUND_INPAINTING_FAILED', OBJECT_REGENERATION_FAILED = 'OBJECT_REGENERATION_FAILED', COPY_REPLACEMENT_FAILED = 'COPY_REPLACEMENT_FAILED', HEADER_COMPOSITION_FAILED = 'HEADER_COMPOSITION_FAILED', PROMPT_GENERATION_FAILED = 'PROMPT_GENERATION_FAILED', TEXT_GENERATION_FAILED = 'TEXT_GENERATION_FAILED', } export class SegmentationError extends Error { constructor( message: string, public code: SegmentationErrorCode, public details?: any, ) { super(message); this.name = 'SegmentationError'; } } export class ValidationError extends Error { constructor( message: string, public field: string, public value?: any, ) { super(message); this.name = 'ValidationError'; } } export interface ErrorResponse { error: { code: string; message: string; details?: any; }; timestamp: string; requestId?: string; } export function createErrorResponse(error: Error, requestId?: string): ErrorResponse { if (error instanceof SegmentationError) { return { error: { code: error.code, message: error.message, details: error.details, }, timestamp: getJSTTimestamp(), requestId, }; } if (error instanceof ValidationError) { return { error: { code: 'VALIDATION_ERROR', message: error.message, details: { field: error.field, value: error.value, }, }, timestamp: getJSTTimestamp(), requestId, }; } // 一般的なエラー return { error: { code: 'INTERNAL_ERROR', message: 'An unexpected error occurred', details: process.env.NODE_ENV === 'development' ? error.message : undefined, }, timestamp: getJSTTimestamp(), requestId, }; } // メモリ使用量をチェック export function checkMemoryUsage(threshold: number = 0.9): void { const usage = process.memoryUsage(); const heapUsed = usage.heapUsed; const heapTotal = usage.heapTotal; const ratio = heapUsed / heapTotal; if (ratio > threshold) { throw new SegmentationError(`Memory usage too high: ${Math.round(ratio * 100)}%`, SegmentationErrorCode.MEMORY_LIMIT_EXCEEDED, { heapUsed, heapTotal, ratio, }); } } // タイムアウト付き処理実行 export async function withTimeout(promise: Promise, timeoutMs: number, operation: string): Promise { const timeoutPromise = new Promise((_, reject) => { setTimeout(() => { reject( new SegmentationError(`Operation '${operation}' timed out after ${timeoutMs}ms`, SegmentationErrorCode.PROCESSING_TIMEOUT, { operation, timeoutMs, }), ); }, timeoutMs); }); return Promise.race([promise, timeoutPromise]); } // リトライ機能付き処理実行 export async function withRetry( fn: () => Promise, options: { maxRetries?: number; delay?: number; backoff?: number; onRetry?: (error: Error, attempt: number) => void; } = {}, ): Promise { const { maxRetries = 3, delay = 1000, backoff = 2, onRetry } = options; let lastError: Error; for (let attempt = 1; attempt <= maxRetries; attempt++) { try { return await fn(); } catch (error) { lastError = error as Error; if (attempt === maxRetries) { throw lastError; } if (onRetry) { onRetry(lastError, attempt); } const waitTime = delay * Math.pow(backoff, attempt - 1); await new Promise((resolve) => setTimeout(resolve, waitTime)); } } throw lastError!; }