修复卡轮训的问题
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 10m14s

This commit is contained in:
2026-04-26 12:41:16 +08:00
parent 7efcea2b54
commit a887f91686
5 changed files with 34 additions and 8 deletions

View File

@@ -226,10 +226,13 @@ func buildActivationStatusExpr(fields map[string]any) any {
return gorm.Expr(`
CASE
WHEN COALESCE(?, network_status) = ?
AND (COALESCE(?, card_category) = ? OR COALESCE(?, real_name_status) = ?)
THEN ?
ELSE ?
WHEN COALESCE(CAST(? AS integer), network_status) = CAST(? AS integer)
AND (
COALESCE(CAST(? AS text), card_category) = CAST(? AS text)
OR COALESCE(CAST(? AS integer), real_name_status) = CAST(? AS integer)
)
THEN CAST(? AS integer)
ELSE CAST(? AS integer)
END`,
networkStatus,
constants.NetworkStatusOnline,
@@ -261,10 +264,13 @@ func buildActivatedAtExpr(fields map[string]any, now time.Time) any {
return gorm.Expr(`
CASE
WHEN activation_status = ?
AND COALESCE(?, network_status) = ?
AND (COALESCE(?, card_category) = ? OR COALESCE(?, real_name_status) = ?)
THEN COALESCE(activated_at, ?)
WHEN activation_status = CAST(? AS integer)
AND COALESCE(CAST(? AS integer), network_status) = CAST(? AS integer)
AND (
COALESCE(CAST(? AS text), card_category) = CAST(? AS text)
OR COALESCE(CAST(? AS integer), real_name_status) = CAST(? AS integer)
)
THEN COALESCE(activated_at, CAST(? AS timestamptz))
ELSE activated_at
END`,
constants.ActivationStatusInactive,

View File

@@ -46,6 +46,14 @@ func (b *PollingBase) updateCardCache(ctx context.Context, cardID uint, updates
}
}
// invalidateCardCache 删除轮询卡缓存,确保后续从数据库重建
func (b *PollingBase) invalidateCardCache(ctx context.Context, cardID uint) {
key := constants.RedisPollingCardInfoKey(cardID)
if err := b.redis.Del(ctx, key).Err(); err != nil {
b.logger.Warn("删除卡缓存失败", zap.Uint("card_id", cardID), zap.Error(err))
}
}
// parseCardFromCache 从 Redis Hash 反序列化卡信息
func parseCardFromCache(cardID uint, result map[string]string) *model.IotCard {
card := &model.IotCard{}

View File

@@ -104,6 +104,9 @@ func (h *PollingCardStatusHandler) Handle(ctx context.Context, t *asynq.Task) er
}
if updateErr := h.iotCardStore.UpdateFields(ctx, cardID, fields); updateErr != nil {
h.base.logger.Warn("更新卡状态信息失败", zap.Uint("card_id", cardID), zap.Error(updateErr))
h.base.invalidateCardCache(ctx, cardID)
h.base.updateStats(ctx, constants.TaskTypePollingCardStatus, false, time.Since(startTime))
return h.base.requeueCard(ctx, cardID, constants.TaskTypePollingCardStatus)
}
if statusChanged {

View File

@@ -107,6 +107,9 @@ func (h *PollingProtectHandler) Handle(ctx context.Context, t *asynq.Task) error
"stop_reason": constants.StopReasonProtectPeriod,
}); updateErr != nil {
h.base.logger.Warn("保护期停机 DB 更新失败", zap.Uint("card_id", cardID), zap.Error(updateErr))
h.base.invalidateCardCache(ctx, cardID)
h.base.updateStats(ctx, constants.TaskTypePollingProtect, false, time.Since(startTime))
return h.base.requeueCard(ctx, cardID, constants.TaskTypePollingProtect)
}
h.base.updateCardCache(ctx, cardID, map[string]any{"network_status": constants.NetworkStatusOffline})
actionTaken = "forced_stop"
@@ -130,6 +133,9 @@ func (h *PollingProtectHandler) Handle(ctx context.Context, t *asynq.Task) error
"stop_reason": "",
}); updateErr != nil {
h.base.logger.Warn("保护期复机 DB 更新失败", zap.Uint("card_id", cardID), zap.Error(updateErr))
h.base.invalidateCardCache(ctx, cardID)
h.base.updateStats(ctx, constants.TaskTypePollingProtect, false, time.Since(startTime))
return h.base.requeueCard(ctx, cardID, constants.TaskTypePollingProtect)
}
h.base.updateCardCache(ctx, cardID, map[string]any{"network_status": constants.NetworkStatusOnline})
actionTaken = "forced_resume"

View File

@@ -129,6 +129,9 @@ func (h *PollingRealnameHandler) Handle(ctx context.Context, t *asynq.Task) erro
}
if err := h.iotCardStore.UpdateFields(ctx, cardID, fields); err != nil {
h.base.logger.Error("更新卡实名信息失败", zap.Uint("card_id", cardID), zap.Error(err))
h.base.invalidateCardCache(ctx, cardID)
h.base.updateStats(ctx, constants.TaskTypePollingRealname, false, time.Since(startTime))
return h.base.requeueCard(ctx, cardID, constants.TaskTypePollingRealname)
}
if statusChanged {