Skip to main content
Glama
lis186

Taiwan Holiday MCP Server

by lis186
error-classifier.ts9.21 kB
/** * Enhanced Error Classification System * * 對錯誤進行分類並提供相應的處理策略 */ import { ErrorType } from '../types.js'; export enum ErrorCategory { /** 暫時性錯誤,可以重試 */ TEMPORARY = 'TEMPORARY', /** 永久性錯誤,不應重試 */ PERMANENT = 'PERMANENT', /** 關鍵錯誤,需要立即處理 */ CRITICAL = 'CRITICAL', /** 預期錯誤,正常業務邏輯 */ EXPECTED = 'EXPECTED' } export enum ErrorSeverity { LOW = 'LOW', MEDIUM = 'MEDIUM', HIGH = 'HIGH', CRITICAL = 'CRITICAL' } export interface RetryStrategy { /** 是否應該重試 */ shouldRetry: boolean; /** 最大重試次數 */ maxRetries: number; /** 重試延遲 (ms) */ retryDelay: number; /** 退避倍數 */ backoffMultiplier: number; /** 最大延遲 (ms) */ maxDelay: number; } export interface ErrorClassification { /** 錯誤類別 */ category: ErrorCategory; /** 嚴重程度 */ severity: ErrorSeverity; /** 錯誤類型 */ type: ErrorType; /** 重試策略 */ retryStrategy: RetryStrategy; /** 是否需要警報 */ needsAlert: boolean; /** 錯誤描述 */ description: string; } /** * 錯誤分類器 */ export class ErrorClassifier { private static readonly HTTP_TEMPORARY_ERRORS = [ 408, // Request Timeout 429, // Too Many Requests 502, // Bad Gateway 503, // Service Unavailable 504, // Gateway Timeout 507, // Insufficient Storage 509, // Bandwidth Limit Exceeded ]; private static readonly HTTP_PERMANENT_ERRORS = [ 400, // Bad Request 401, // Unauthorized 403, // Forbidden 404, // Not Found 405, // Method Not Allowed 406, // Not Acceptable 409, // Conflict 410, // Gone 413, // Payload Too Large 414, // URI Too Long 415, // Unsupported Media Type 422, // Unprocessable Entity ]; /** * 分類錯誤 */ static classify(error: Error): ErrorClassification { // 網路錯誤 if (this.isNetworkError(error)) { return this.classifyNetworkError(error); } // HTTP 錯誤 if (this.isHttpError(error)) { return this.classifyHttpError(error); } // 解析錯誤 if (this.isParseError(error)) { return this.classifyParseError(error); } // 驗證錯誤 if (this.isValidationError(error)) { return this.classifyValidationError(error); } // 超時錯誤 if (this.isTimeoutError(error)) { return this.classifyTimeoutError(error); } // 系統錯誤 if (this.isSystemError(error)) { return this.classifySystemError(error); } // 預設分類 return this.getDefaultClassification(error); } /** * 檢查是否為網路錯誤 */ private static isNetworkError(error: Error): boolean { const networkErrorCodes = ['ECONNRESET', 'ENOTFOUND', 'ECONNREFUSED', 'ETIMEDOUT']; return networkErrorCodes.some(code => error.message.includes(code)); } /** * 分類網路錯誤 */ // eslint-disable-next-line @typescript-eslint/no-unused-vars private static classifyNetworkError(_error: Error): ErrorClassification { return { category: ErrorCategory.TEMPORARY, severity: ErrorSeverity.MEDIUM, type: ErrorType.NETWORK_ERROR, retryStrategy: { shouldRetry: true, maxRetries: 3, retryDelay: 1000, backoffMultiplier: 2, maxDelay: 10000, }, needsAlert: false, description: '網路連線錯誤,將自動重試', }; } /** * 檢查是否為 HTTP 錯誤 */ private static isHttpError(error: Error): boolean { return error.message.includes('HTTP') || /^\d{3}/.test(error.message); } /** * 分類 HTTP 錯誤 */ private static classifyHttpError(error: Error): ErrorClassification { const statusMatch = error.message.match(/(\d{3})/); const status = statusMatch ? parseInt(statusMatch[1]) : 500; if (this.HTTP_TEMPORARY_ERRORS.includes(status)) { return { category: ErrorCategory.TEMPORARY, severity: status >= 500 ? ErrorSeverity.HIGH : ErrorSeverity.MEDIUM, type: ErrorType.API_ERROR, retryStrategy: { shouldRetry: true, maxRetries: status === 429 ? 2 : 3, retryDelay: status === 429 ? 5000 : 2000, backoffMultiplier: 2, maxDelay: 30000, }, needsAlert: status >= 500, description: `HTTP ${status} 錯誤,將自動重試`, }; } if (this.HTTP_PERMANENT_ERRORS.includes(status)) { return { category: ErrorCategory.PERMANENT, severity: ErrorSeverity.MEDIUM, type: ErrorType.API_ERROR, retryStrategy: { shouldRetry: false, maxRetries: 0, retryDelay: 0, backoffMultiplier: 1, maxDelay: 0, }, needsAlert: false, description: `HTTP ${status} 錯誤,不會重試`, }; } // 5xx 伺服器錯誤 if (status >= 500) { return { category: ErrorCategory.TEMPORARY, severity: ErrorSeverity.HIGH, type: ErrorType.API_ERROR, retryStrategy: { shouldRetry: true, maxRetries: 2, retryDelay: 3000, backoffMultiplier: 2, maxDelay: 15000, }, needsAlert: true, description: `HTTP ${status} 伺服器錯誤,將重試`, }; } return this.getDefaultClassification(error); } /** * 檢查是否為解析錯誤 */ private static isParseError(error: Error): boolean { return error.name.includes('Parse') || error.message.includes('parse') || error.message.includes('JSON'); } /** * 分類解析錯誤 */ // eslint-disable-next-line @typescript-eslint/no-unused-vars private static classifyParseError(_error: Error): ErrorClassification { return { category: ErrorCategory.TEMPORARY, severity: ErrorSeverity.MEDIUM, type: ErrorType.PARSE_ERROR, retryStrategy: { shouldRetry: true, maxRetries: 1, retryDelay: 1000, backoffMultiplier: 1, maxDelay: 1000, }, needsAlert: false, description: '資料解析錯誤,可能是暫時性問題', }; } /** * 檢查是否為驗證錯誤 */ private static isValidationError(error: Error): boolean { return error.name.includes('Validation') || error.message.includes('validation') || error.message.includes('invalid'); } /** * 分類驗證錯誤 */ // eslint-disable-next-line @typescript-eslint/no-unused-vars private static classifyValidationError(_error: Error): ErrorClassification { return { category: ErrorCategory.EXPECTED, severity: ErrorSeverity.LOW, type: ErrorType.VALIDATION_ERROR, retryStrategy: { shouldRetry: false, maxRetries: 0, retryDelay: 0, backoffMultiplier: 1, maxDelay: 0, }, needsAlert: false, description: '輸入驗證錯誤,請檢查參數格式', }; } /** * 檢查是否為超時錯誤 */ private static isTimeoutError(error: Error): boolean { return error.message.includes('timeout') || error.message.includes('ETIMEDOUT'); } /** * 分類超時錯誤 */ // eslint-disable-next-line @typescript-eslint/no-unused-vars private static classifyTimeoutError(_error: Error): ErrorClassification { return { category: ErrorCategory.TEMPORARY, severity: ErrorSeverity.MEDIUM, type: ErrorType.TIMEOUT_ERROR, retryStrategy: { shouldRetry: true, maxRetries: 2, retryDelay: 2000, backoffMultiplier: 2, maxDelay: 8000, }, needsAlert: false, description: '請求超時,將自動重試', }; } /** * 檢查是否為系統錯誤 */ private static isSystemError(error: Error): boolean { return error.name === 'Error' && ( error.message.includes('memory') || error.message.includes('EMFILE') || error.message.includes('ENOMEM') ); } /** * 分類系統錯誤 */ // eslint-disable-next-line @typescript-eslint/no-unused-vars private static classifySystemError(_error: Error): ErrorClassification { return { category: ErrorCategory.CRITICAL, severity: ErrorSeverity.CRITICAL, type: ErrorType.SYSTEM_ERROR, retryStrategy: { shouldRetry: false, maxRetries: 0, retryDelay: 0, backoffMultiplier: 1, maxDelay: 0, }, needsAlert: true, description: '系統錯誤,需要立即處理', }; } /** * 獲取預設分類 */ // eslint-disable-next-line @typescript-eslint/no-unused-vars private static getDefaultClassification(_error: Error): ErrorClassification { return { category: ErrorCategory.TEMPORARY, severity: ErrorSeverity.MEDIUM, type: ErrorType.UNKNOWN_ERROR, retryStrategy: { shouldRetry: true, maxRetries: 1, retryDelay: 1000, backoffMultiplier: 1, maxDelay: 1000, }, needsAlert: false, description: '未知錯誤,將嘗試重試一次', }; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/lis186/taiwan-holiday-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server