fix: persist guest/redemption activation context to DB to survive Redis TTL expiry (Bug 1 + Bug 10)

- Add `activation_context` TEXT column to `order` table (migration 02150)
- purchaseLogic: write TemporaryOrderInfo JSON to order.ActivationContext in the same
  insert transaction; Redis write is now best-effort (non-fatal)
- redeemCodeLogic: write redemption {type, redemption_code_id, unit_time, quantity} JSON
  to order.ActivationContext at order creation; Redis write is now best-effort (non-fatal)
- getTempOrderInfo: on Redis miss, fall back to order.ActivationContext from DB;
  logs CRITICAL and returns error if both are missing (old orders with no DB record)
- RedemptionActivate: on Redis miss, fall back to order.ActivationContext from DB;
  same CRITICAL log path for legacy orders

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
2026-05-25 00:13:59 -07:00
parent 30221232c9
commit a0f2d8a7b8
6 changed files with 130 additions and 61 deletions
@@ -154,9 +154,12 @@ func (l *PurchaseLogic) Purchase(req *types.PortalPurchaseRequest) (resp *types.
}
content, _ := tempOrder.Marshal()
if _, err = l.svcCtx.Redis.Set(l.ctx, fmt.Sprintf(constant.TempOrderCacheKey, orderInfo.OrderNo), string(content), CloseOrderTimeMinutes*time.Minute).Result(); err != nil {
l.Errorw("[Purchase] Redis set error", logger.Field("error", err.Error()), logger.Field("order_no", orderInfo.OrderNo))
return err
// Persist activation context to DB so the worker can recover if Redis TTL expires.
orderInfo.ActivationContext = string(content)
// Write to Redis as a hot cache (best-effort; non-fatal on failure).
if _, redisErr := l.svcCtx.Redis.Set(l.ctx, fmt.Sprintf(constant.TempOrderCacheKey, orderInfo.OrderNo), string(content), CloseOrderTimeMinutes*time.Minute).Result(); redisErr != nil {
l.Infow("[Purchase] Redis set error (non-fatal, DB fallback available)", logger.Field("error", redisErr.Error()), logger.Field("order_no", orderInfo.OrderNo))
}
l.Infow("[Purchase] Guest order", logger.Field("order_no", orderInfo.OrderNo), logger.Field("identifier", req.Identifier))
@@ -169,7 +172,7 @@ func (l *PurchaseLogic) Purchase(req *types.PortalPurchaseRequest) (resp *types.
}
}
// save guest order
// save guest order (activation_context is included)
if err = l.svcCtx.OrderModel.Insert(l.ctx, orderInfo, tx); err != nil {
return err
}