Documentation
¶
Overview ¶
Package verification 邮箱验证码的 Redis 存储(spec 2026-08-25-emailcode-redis-migration §2):一个 (purpose,email) 一个 HASH,四命令直映 service.EmailCodeStore,零 Lua。
key c3api:emailcode:<purpose>:<email>
fields code_sha256 / attempts / updated_at(unixmilli)
expiry EXPIREAT <expires_at> —— 原生 TTL 取代 PG 版 expires_at 列的判定职责,
过期键由 Redis 删除 ⇒ Get 返回 (nil,nil) ⇒ 服务层走 "code invalid" 分支。
客户端经构造注入不自建(pkg/redisx 单点构造纪律);Redis 必选依赖 ⇒ 无 nil 分支。
Index ¶
- type Store
- func (s *Store) DeleteEmailCode(ctx context.Context, email, purpose string) error
- func (s *Store) GetEmailCode(ctx context.Context, email, purpose string) (*domain.EmailCode, error)
- func (s *Store) IncrementEmailCodeAttempts(ctx context.Context, email, purpose string) (int, error)
- func (s *Store) UpsertEmailCode(ctx context.Context, email, purpose, sha256 string, expiresAt time.Time) (*domain.EmailCode, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store 验证码存储:实现 service.EmailCodeStore 四方法(语义与 PG 版逐条对齐, spec §2 映射表)。
func (*Store) DeleteEmailCode ¶
DeleteEmailCode DEL(键不存在返回 0 不报错——消费/过期清理幂等,调用方均忽略错误)。
func (*Store) GetEmailCode ¶
GetEmailCode HGETALL + PTTL 同管线取行;键不存在/已过期(含两命令间隙被删) 返回 (nil,nil)。ExpiresAt 由剩余 PTTL 重构——过期键已被删除,服务层过期分支 成为死路径(spec §2.1 取舍①),重构值仅供结构完整。
func (*Store) IncrementEmailCodeAttempts ¶
IncrementEmailCodeAttempts HINCRBY 自增并返回新值。HINCRBY 不触碰 TTL——剩余 有效期保持(spec §2 映射表)。并发说明(spec §2):键在 Get 后恰好过期的极端 竞态下 HINCRBY 会新建无 TTL 的孤儿 HASH,最坏多计一次 attempts(方向保守), 成功双删幂等——直映不引入新竞态,无需 Lua/WATCH。
func (*Store) UpsertEmailCode ¶
func (s *Store) UpsertEmailCode(ctx context.Context, email, purpose, sha256 string, expiresAt time.Time) (*domain.EmailCode, error)
UpsertEmailCode 覆盖写三字段 + EXPIREAT:覆盖 ⇒ attempts 归零、旧码失效; updated_at 刷新 ⇒ 60s 重发抑制滑窗(spec §2 映射表)。返回组装的行(调用方 忽略返回值,仅用 error)。 两命令走 TxPipeline(MULTI/EXEC——非 Lua/WATCH,不违 spec 裁决):原子消除了 「HSET 成功后崩溃残留无 TTL 孤儿」窗口(审查发现①),顺带省 1 RTT。