初始化v1
This commit is contained in:
312
utility/recovery/recovery.go
Normal file
312
utility/recovery/recovery.go
Normal file
@@ -0,0 +1,312 @@
|
||||
package recovery
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"nl-video-api/utility/response"
|
||||
)
|
||||
|
||||
// RecoveryMiddleware 恢复中间件
|
||||
func RecoveryMiddleware(r *ghttp.Request) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
// 记录panic信息
|
||||
LogPanic(r.Context(), err)
|
||||
|
||||
// 返回统一错误响应
|
||||
response.JsonExit(r, 1007, "服务器内部错误")
|
||||
}
|
||||
}()
|
||||
|
||||
r.Middleware.Next()
|
||||
}
|
||||
|
||||
// LogPanic 记录panic信息
|
||||
func LogPanic(ctx context.Context, err interface{}) {
|
||||
// 获取调用栈信息
|
||||
stack := getStack(3)
|
||||
|
||||
// 记录详细的panic信息
|
||||
g.Log().Error(ctx, "System Panic Recovered", g.Map{
|
||||
"error": fmt.Sprintf("%v", err),
|
||||
"stack": stack,
|
||||
"timestamp": gtime.Now().String(),
|
||||
})
|
||||
|
||||
// 发送告警通知(可以集成钉钉、邮件等)
|
||||
sendAlertNotification(ctx, err, stack)
|
||||
}
|
||||
|
||||
// getStack 获取调用栈
|
||||
func getStack(skip int) string {
|
||||
var buf strings.Builder
|
||||
|
||||
for i := skip; ; i++ {
|
||||
pc, file, line, ok := runtime.Caller(i)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
fn := runtime.FuncForPC(pc)
|
||||
if fn == nil {
|
||||
buf.WriteString("unknown function\n")
|
||||
} else {
|
||||
buf.WriteString(fmt.Sprintf("%s:%d %s\n", file, line, fn.Name()))
|
||||
}
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// sendAlertNotification 发送告警通知
|
||||
func sendAlertNotification(ctx context.Context, err interface{}, stack string) {
|
||||
// 这里可以集成各种告警通知方式
|
||||
// 例如:钉钉机器人、邮件、短信等
|
||||
|
||||
g.Log().Warning(ctx, "Alert Notification", g.Map{
|
||||
"type": "panic_recovery",
|
||||
"error": fmt.Sprintf("%v", err),
|
||||
"message": "系统发生panic,已自动恢复",
|
||||
})
|
||||
}
|
||||
|
||||
// ErrorHandler 统一错误处理器
|
||||
type ErrorHandler struct {
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewErrorHandler 创建错误处理器
|
||||
func NewErrorHandler(ctx context.Context) *ErrorHandler {
|
||||
return &ErrorHandler{ctx: ctx}
|
||||
}
|
||||
|
||||
// HandleError 处理错误
|
||||
func (e *ErrorHandler) HandleError(err error, operation string) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 记录错误信息
|
||||
g.Log().Error(e.ctx, "Operation Error", g.Map{
|
||||
"operation": operation,
|
||||
"error": err.Error(),
|
||||
"timestamp": gtime.Now().String(),
|
||||
})
|
||||
|
||||
// 根据错误类型进行不同处理
|
||||
e.categorizeError(err, operation)
|
||||
}
|
||||
|
||||
// categorizeError 错误分类处理
|
||||
func (e *ErrorHandler) categorizeError(err error, operation string) {
|
||||
errMsg := err.Error()
|
||||
|
||||
switch {
|
||||
case strings.Contains(errMsg, "connection refused"):
|
||||
e.handleConnectionError(err, operation)
|
||||
case strings.Contains(errMsg, "timeout"):
|
||||
e.handleTimeoutError(err, operation)
|
||||
case strings.Contains(errMsg, "duplicate"):
|
||||
e.handleDuplicateError(err, operation)
|
||||
case strings.Contains(errMsg, "not found"):
|
||||
e.handleNotFoundError(err, operation)
|
||||
default:
|
||||
e.handleGenericError(err, operation)
|
||||
}
|
||||
}
|
||||
|
||||
// handleConnectionError 处理连接错误
|
||||
func (e *ErrorHandler) handleConnectionError(err error, operation string) {
|
||||
g.Log().Error(e.ctx, "Connection Error", g.Map{
|
||||
"operation": operation,
|
||||
"error": err.Error(),
|
||||
"type": "connection",
|
||||
"action": "retry_connection",
|
||||
})
|
||||
}
|
||||
|
||||
// handleTimeoutError 处理超时错误
|
||||
func (e *ErrorHandler) handleTimeoutError(err error, operation string) {
|
||||
g.Log().Error(e.ctx, "Timeout Error", g.Map{
|
||||
"operation": operation,
|
||||
"error": err.Error(),
|
||||
"type": "timeout",
|
||||
"action": "increase_timeout",
|
||||
})
|
||||
}
|
||||
|
||||
// handleDuplicateError 处理重复错误
|
||||
func (e *ErrorHandler) handleDuplicateError(err error, operation string) {
|
||||
g.Log().Warning(e.ctx, "Duplicate Error", g.Map{
|
||||
"operation": operation,
|
||||
"error": err.Error(),
|
||||
"type": "duplicate",
|
||||
"action": "check_uniqueness",
|
||||
})
|
||||
}
|
||||
|
||||
// handleNotFoundError 处理未找到错误
|
||||
func (e *ErrorHandler) handleNotFoundError(err error, operation string) {
|
||||
g.Log().Info(e.ctx, "Not Found Error", g.Map{
|
||||
"operation": operation,
|
||||
"error": err.Error(),
|
||||
"type": "not_found",
|
||||
"action": "verify_resource",
|
||||
})
|
||||
}
|
||||
|
||||
// handleGenericError 处理通用错误
|
||||
func (e *ErrorHandler) handleGenericError(err error, operation string) {
|
||||
g.Log().Error(e.ctx, "Generic Error", g.Map{
|
||||
"operation": operation,
|
||||
"error": err.Error(),
|
||||
"type": "generic",
|
||||
"action": "manual_review",
|
||||
})
|
||||
}
|
||||
|
||||
// RetryHandler 重试处理器
|
||||
type RetryHandler struct {
|
||||
maxRetries int
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewRetryHandler 创建重试处理器
|
||||
func NewRetryHandler(ctx context.Context, maxRetries int) *RetryHandler {
|
||||
return &RetryHandler{
|
||||
maxRetries: maxRetries,
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// ExecuteWithRetry 带重试的执行
|
||||
func (r *RetryHandler) ExecuteWithRetry(operation func() error, operationName string) error {
|
||||
var lastErr error
|
||||
|
||||
for i := 0; i <= r.maxRetries; i++ {
|
||||
err := operation()
|
||||
if err == nil {
|
||||
if i > 0 {
|
||||
g.Log().Info(r.ctx, "Operation Succeeded After Retry", g.Map{
|
||||
"operation": operationName,
|
||||
"retry_count": i,
|
||||
"max_retries": r.maxRetries,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
lastErr = err
|
||||
|
||||
if i < r.maxRetries {
|
||||
g.Log().Warning(r.ctx, "Operation Failed, Retrying", g.Map{
|
||||
"operation": operationName,
|
||||
"error": err.Error(),
|
||||
"retry_count": i + 1,
|
||||
"max_retries": r.maxRetries,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
g.Log().Error(r.ctx, "Operation Failed After All Retries", g.Map{
|
||||
"operation": operationName,
|
||||
"error": lastErr.Error(),
|
||||
"max_retries": r.maxRetries,
|
||||
})
|
||||
|
||||
return lastErr
|
||||
}
|
||||
|
||||
// CircuitBreaker 熔断器
|
||||
type CircuitBreaker struct {
|
||||
failureCount int
|
||||
successCount int
|
||||
failureThreshold int
|
||||
resetTimeout int64
|
||||
lastFailureTime int64
|
||||
state string // "closed", "open", "half-open"
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewCircuitBreaker 创建熔断器
|
||||
func NewCircuitBreaker(ctx context.Context, failureThreshold int, resetTimeout int64) *CircuitBreaker {
|
||||
return &CircuitBreaker{
|
||||
failureThreshold: failureThreshold,
|
||||
resetTimeout: resetTimeout,
|
||||
state: "closed",
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// Execute 执行操作
|
||||
func (cb *CircuitBreaker) Execute(operation func() error, operationName string) error {
|
||||
if cb.state == "open" {
|
||||
if gtime.Now().Unix()-cb.lastFailureTime > cb.resetTimeout {
|
||||
cb.state = "half-open"
|
||||
cb.successCount = 0
|
||||
g.Log().Info(cb.ctx, "Circuit Breaker Half-Open", g.Map{
|
||||
"operation": operationName,
|
||||
"state": cb.state,
|
||||
})
|
||||
} else {
|
||||
return fmt.Errorf("circuit breaker is open for operation: %s", operationName)
|
||||
}
|
||||
}
|
||||
|
||||
err := operation()
|
||||
|
||||
if err != nil {
|
||||
cb.onFailure(operationName)
|
||||
return err
|
||||
}
|
||||
|
||||
cb.onSuccess(operationName)
|
||||
return nil
|
||||
}
|
||||
|
||||
// onSuccess 成功回调
|
||||
func (cb *CircuitBreaker) onSuccess(operationName string) {
|
||||
cb.successCount++
|
||||
|
||||
if cb.state == "half-open" && cb.successCount >= 3 {
|
||||
cb.state = "closed"
|
||||
cb.failureCount = 0
|
||||
g.Log().Info(cb.ctx, "Circuit Breaker Closed", g.Map{
|
||||
"operation": operationName,
|
||||
"state": cb.state,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// onFailure 失败回调
|
||||
func (cb *CircuitBreaker) onFailure(operationName string) {
|
||||
cb.failureCount++
|
||||
cb.lastFailureTime = gtime.Now().Unix()
|
||||
|
||||
if cb.failureCount >= cb.failureThreshold {
|
||||
cb.state = "open"
|
||||
g.Log().Warning(cb.ctx, "Circuit Breaker Opened", g.Map{
|
||||
"operation": operationName,
|
||||
"state": cb.state,
|
||||
"failure_count": cb.failureCount,
|
||||
"failure_threshold": cb.failureThreshold,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// GetState 获取熔断器状态
|
||||
func (cb *CircuitBreaker) GetState() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"state": cb.state,
|
||||
"failure_count": cb.failureCount,
|
||||
"success_count": cb.successCount,
|
||||
"failure_threshold": cb.failureThreshold,
|
||||
"last_failure_time": cb.lastFailureTime,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user