Files
backend/internal/model/push_record.go
lan ee78071d4d
All checks were successful
Build Backend / build (push) Successful in 3m2s
Build Backend / build-docker (push) Successful in 2m44s
refactor: improve system stability, performance, and code structure
This commit introduces several architectural improvements and optimizations across the codebase:

- **Performance & Reliability**:
  - Implemented Redis pipelining in `ConversationCache.CacheMessage` to reduce network round-trips.
  - Added a circuit breaker to the JPush client to prevent cascading failures.
  - Introduced batch deletion and batch member addition capabilities in repositories.
  - Added message idempotency support using `client_msg_id` and a Redis-based cache.
  - Optimized WebSocket handling with connection limits (total and per-user) and improved error logging.

- **Code Refactoring**:
  - Refactored `Router` to use a `RouterDeps` struct, simplifying the constructor and improving maintainability.
  - Unified model ID generation logic using new `id_helper.go` (supporting UUID and Snowflake).
  - Standardized JSON serialization/deserialization in models using `json_helper.go`.
  - Refactored DTO conversion logic, specifically for `UserResponse` (using functional options) and `Report` responses.
  - Removed redundant/deprecated DTOs like `PostDetailResponse` and `TradeItemDetailResponse`.

- **Cache Improvements**:
  - Enhanced `LayeredCache` with `SetRaw` to avoid double-encoding when promoting values from Redis to local cache.
  - Added `DeleteBatch` support to the cache interface.

- **Other Changes**:
  - Cleaned up `config.go` by removing redundant default values and explicit environment variable overrides.
  - Improved WebSocket registration flow to handle connection limits gracefully.
2026-05-04 13:07:03 +08:00

122 lines
3.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package model
import (
"time"
"gorm.io/gorm"
)
// PushChannel 推送通道类型
type PushChannel string
const (
PushChannelWebSocket PushChannel = "websocket" // WebSocket推送
PushChannelFCM PushChannel = "fcm" // Firebase Cloud Messaging
PushChannelAPNs PushChannel = "apns" // Apple Push Notification service
PushChannelHuawei PushChannel = "huawei" // 华为推送
PushChannelJPush PushChannel = "jpush" // 极光推送
)
// PushStatus 推送状态
type PushStatus string
const (
PushStatusPending PushStatus = "pending" // 待推送
PushStatusPushing PushStatus = "pushing" // 推送中
PushStatusPushed PushStatus = "pushed" // 已推送(成功发送到推送服务)
PushStatusDelivered PushStatus = "delivered" // 已送达(客户端确认)
PushStatusFailed PushStatus = "failed" // 推送失败
PushStatusExpired PushStatus = "expired" // 消息过期
)
// PushRecord 推送记录实体
// 用于跟踪消息的推送状态,支持多设备推送和重试机制
type PushRecord struct {
ID int64 `gorm:"primaryKey;autoIncrement:false" json:"id"` // 雪花算法ID
UserID string `gorm:"column:user_id;type:varchar(50);index;not null" json:"user_id"` // 目标用户ID (UUID格式)
MessageID string `gorm:"index;not null;size:20" json:"message_id"` // 关联的消息ID (string类型)
PushChannel PushChannel `gorm:"type:varchar(20);not null" json:"push_channel"` // 推送通道
PushStatus PushStatus `gorm:"type:varchar(20);not null;default:'pending'" json:"push_status"` // 推送状态
// 设备信息
DeviceToken string `gorm:"type:varchar(256)" json:"device_token,omitempty"` // 设备Token用于手机推送
DeviceType string `gorm:"type:varchar(20)" json:"device_type,omitempty"` // 设备类型 (ios/android/web)
// 重试机制
RetryCount int `gorm:"default:0" json:"retry_count"` // 重试次数
MaxRetry int `gorm:"default:3" json:"max_retry"` // 最大重试次数
// 时间戳
PushedAt *time.Time `json:"pushed_at,omitempty"` // 推送时间
DeliveredAt *time.Time `json:"delivered_at,omitempty"` // 送达时间
ExpiredAt *time.Time `gorm:"index" json:"expired_at,omitempty"` // 过期时间
// 错误信息
ErrorMessage string `gorm:"type:varchar(500)" json:"error_message,omitempty"` // 错误信息
// 软删除
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
// 时间戳
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
}
// BeforeCreate 创建前生成雪花算法ID
func (r *PushRecord) BeforeCreate(tx *gorm.DB) error {
return SetSnowflakeInt64ID(&r.ID)
}
func (PushRecord) TableName() string {
return "push_records"
}
// CanRetry 判断是否可以重试
func (r *PushRecord) CanRetry() bool {
return r.RetryCount < r.MaxRetry && r.PushStatus != PushStatusDelivered && r.PushStatus != PushStatusExpired
}
// IsExpired 判断是否已过期
func (r *PushRecord) IsExpired() bool {
if r.ExpiredAt == nil {
return false
}
return time.Now().After(*r.ExpiredAt)
}
// MarkPushing 标记为推送中
func (r *PushRecord) MarkPushing() {
r.PushStatus = PushStatusPushing
}
// MarkPushed 标记为已推送
func (r *PushRecord) MarkPushed() {
now := time.Now()
r.PushStatus = PushStatusPushed
r.PushedAt = &now
}
// MarkDelivered 标记为已送达
func (r *PushRecord) MarkDelivered() {
now := time.Now()
r.PushStatus = PushStatusDelivered
r.DeliveredAt = &now
}
// MarkFailed 标记为推送失败
func (r *PushRecord) MarkFailed(errMsg string) {
r.PushStatus = PushStatusFailed
r.ErrorMessage = errMsg
r.RetryCount++
}
// MarkExpired 标记为已过期
func (r *PushRecord) MarkExpired() {
r.PushStatus = PushStatusExpired
}
// IncrementRetry 增加重试次数
func (r *PushRecord) IncrementRetry() {
r.RetryCount++
}