FE_Test / services /errors.ts
GitHub Actions
Deploy from GitHub Actions [test] - 2025-10-31 10:18:25
5f2aab6
/**
* 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<T>(promise: Promise<T>, timeoutMs: number, operation: string): Promise<T> {
const timeoutPromise = new Promise<never>((_, 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<T>(
fn: () => Promise<T>,
options: {
maxRetries?: number;
delay?: number;
backoff?: number;
onRetry?: (error: Error, attempt: number) => void;
} = {},
): Promise<T> {
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!;
}