我来详细分析这个授权过期提醒策略需求,并提供完整的Go语言实现方案。
需求分析
核心目标
- 完善授权到期前后的提醒机制
- 分阶段提醒:到期前60天、30天、15天、到期后、超期7天
- 差异化提醒对象:平台管理员/租户管理员 vs 所有用户
- 不同触发频率:每月、每天、每次登录、每个请求
- 提醒不阻塞业务(除超期后的概率异常)
策略阶段分析
| 阶段 | 时间区间 | 提醒对象 | 触发条件 | 业务影响 | |——|———-|———-|———-|———-| | 阶段1 | 到期前60天开始 | 平台/租户管理员 | 每月一次,登录时 | 不阻塞 | | 阶段2 | 到期前30天开始 | 平台/租户管理员 | 每天一次,登录时 | 不阻塞 | | 阶段3 | 到期前15天开始 | 平台/租户管理员 | 每次登录时 | 不阻塞 | | 阶段4 | 到期后0天开始 | 所有用户 + 平台/租户管理员 | 所有请求 + 登录时 | 概率阻塞 | | 阶段5 | 超期7天开始 | 所有用户 + 平台/租户管理员 | 所有请求 + 登录时 | 概率阻塞 |
Go语言实现方案
1. 数据结构定义
package main
import (
"fmt"
"time"
"math/rand"
)
// 许可证信息
type License struct {
ExpireTime time.Time
IsValid bool
LicenseType string
}
// 用户信息
type User struct {
ID string
Username string
Role UserRole
LastRemind map[RemindStage]time.Time
}
// 用户角色
type UserRole int
const (
RoleNormalUser UserRole = iota
RoleTenantAdmin
RolePlatformAdmin
)
// 提醒阶段
type RemindStage int
const (
Stage60DaysBefore RemindStage = iota
Stage30DaysBefore
Stage15DaysBefore
StageAfterExpire
Stage7DaysAfterExpire
)
// 提醒策略配置
type RemindStrategy struct {
Stage RemindStage
DaysFromExpire int // 正数表示到期前,负数表示到期后
TargetUsers []UserRole
TriggerCondition string
Frequency time.Duration
MessageTemplate string
BlockBusiness bool
ExceptionRate float64 // 异常抛出概率(0-1)
}
// 提醒记录
type RemindRecord struct {
UserID string
Stage RemindStage
RemindTime time.Time
Message string
IsShown bool
}
2. 策略配置管理
// 策略管理器
type RemindStrategyManager struct {
strategies map[RemindStage]*RemindStrategy
license *License
remindHistory map[string][]*RemindRecord // userID -> records
}
func NewRemindStrategyManager(license *License) *RemindStrategyManager {
manager := &RemindStrategyManager{
license: license,
strategies: make(map[RemindStage]*RemindStrategy),
remindHistory: make(map[string][]*RemindRecord),
}
manager.initStrategies()
return manager
}
func (m *RemindStrategyManager) initStrategies() {
// 阶段1: 到期前60天开始
m.strategies[Stage60DaysBefore] = &RemindStrategy{
Stage: Stage60DaysBefore,
DaysFromExpire: 60,
TargetUsers: []UserRole{RolePlatformAdmin, RoleTenantAdmin},
TriggerCondition: "登录时",
Frequency: time.Hour * 24 * 30, // 每月一次
MessageTemplate: "平台许可证将在%d天后,%s到期,为避免到期后系统不能正常使用而影响业务,请在到期前及时进行许可证续期。",
BlockBusiness: false,
ExceptionRate: 0,
}
// 阶段2: 到期前30天开始
m.strategies[Stage30DaysBefore] = &RemindStrategy{
Stage: Stage30DaysBefore,
DaysFromExpire: 30,
TargetUsers: []UserRole{RolePlatformAdmin, RoleTenantAdmin},
TriggerCondition: "登录时",
Frequency: time.Hour * 24, // 每天一次
MessageTemplate: "平台许可证将在%d天后,%s到期,为避免到期后系统不能正常使用而影响业务,请在到期前及时进行许可证续期。",
BlockBusiness: false,
ExceptionRate: 0,
}
// 阶段3: 到期前15天开始
m.strategies[Stage15DaysBefore] = &RemindStrategy{
Stage: Stage15DaysBefore,
DaysFromExpire: 15,
TargetUsers: []UserRole{RolePlatformAdmin, RoleTenantAdmin},
TriggerCondition: "登录时",
Frequency: time.Hour * 1, // 每次登录(按小时频率)
MessageTemplate: "平台许可证将在%d天后,%s到期,为避免到期后系统不能正常使用而影响业务,请在到期前及时进行许可证续期。",
BlockBusiness: false,
ExceptionRate: 0,
}
// 阶段4: 到期后
m.strategies[StageAfterExpire] = &RemindStrategy{
Stage: StageAfterExpire,
DaysFromExpire: 0,
TargetUsers: []UserRole{RolePlatformAdmin, RoleTenantAdmin, RoleNormalUser},
TriggerCondition: "所有请求",
Frequency: time.Hour * 1,
MessageTemplate: "平台许可证已于%s到期,请在7天内完成许可证续期,否则系统将在%s后不能正常使用!",
BlockBusiness: true,
ExceptionRate: 0.3, // 30%概率抛异常
}
// 阶段5: 超期7天开始
m.strategies[Stage7DaysAfterExpire] = &RemindStrategy{
Stage: Stage7DaysAfterExpire,
DaysFromExpire: -7,
TargetUsers: []UserRole{RolePlatformAdmin, RoleTenantAdmin, RoleNormalUser},
TriggerCondition: "所有请求",
Frequency: time.Hour * 1,
MessageTemplate: "平台许可证已过期,系统不能正常使用,请联系您的系统管理员进行处理!",
BlockBusiness: true,
ExceptionRate: 0.5, // 50%概率抛异常
}
}
3. 核心业务逻辑
// 获取当前提醒阶段
func (m *RemindStrategyManager) getCurrentStage() RemindStage {
now := time.Now()
daysUntilExpire := int(m.license.ExpireTime.Sub(now).Hours() / 24)
switch {
case daysUntilExpire >= 60:
return Stage60DaysBefore
case daysUntilExpire >= 30:
return Stage30DaysBefore
case daysUntilExpire >= 15:
return Stage15DaysBefore
case daysUntilExpire >= 0:
return StageAfterExpire
default:
if daysUntilExpire <= -7 {
return Stage7DaysAfterExpire
}
return StageAfterExpire
}
}
// 检查用户是否需要提醒
func (m *RemindStrategyManager) shouldRemindUser(user *User, stage RemindStage, triggerType string) bool {
strategy, exists := m.strategies[stage]
if !exists {
return false
}
// 检查触发条件
if triggerType != strategy.TriggerCondition && strategy.TriggerCondition != "所有请求" {
return false
}
// 检查用户角色
userInTarget := false
for _, role := range strategy.TargetUsers {
if user.Role == role {
userInTarget = true
break
}
}
if !userInTarget {
return false
}
// 检查频率限制
lastRemind, exists := user.LastRemind[stage]
if exists && time.Since(lastRemind) < strategy.Frequency {
return false
}
return true
}
// 生成提醒消息
func (m *RemindStrategyManager) generateMessage(stage RemindStage, user *User) string {
strategy := m.strategies[stage]
expireTimeStr := m.license.ExpireTime.Format("2006年01月02日 15:04:05")
daysUntil := int(m.license.ExpireTime.Sub(time.Now()).Hours() / 24)
switch stage {
case Stage60DaysBefore, Stage30DaysBefore, Stage15DaysBefore:
return fmt.Sprintf(strategy.MessageTemplate, daysUntil, expireTimeStr)
case StageAfterExpire:
deadline := m.license.ExpireTime.AddDate(0, 0, 7)
return fmt.Sprintf(strategy.MessageTemplate, expireTimeStr, deadline.Format("2006年01月02日 15:04:05"))
case Stage7DaysAfterExpire:
if user.Role == RoleNormalUser {
return "平台许可证已过期,系统不能正常使用,请联系您的系统管理员进行处理!"
} else {
return fmt.Sprintf("平台许可证已于%s到期,经多次提醒贵司未能在宽限期内完成许可证续期,系统已不能正常使用!", expireTimeStr)
}
default:
return "许可证状态异常,请联系管理员。"
}
}
// 处理业务阻塞逻辑
func (m *RemindStrategyManager) checkBusinessBlock(stage RemindStage) error {
strategy := m.strategies[stage]
if strategy.BlockBusiness && rand.Float64() < strategy.ExceptionRate {
return fmt.Errorf("许可证已过期,系统不能正常使用")
}
return nil
}
4. API接口实现
// 登录提醒处理
func (m *RemindStrategyManager) HandleLoginRemind(user *User) (*RemindRecord, error) {
stage := m.getCurrentStage()
if !m.shouldRemindUser(user, stage, "登录时") {
return nil, nil
}
// 检查业务阻塞
if err := m.checkBusinessBlock(stage); err != nil {
return nil, err
}
message := m.generateMessage(stage, user)
record := &RemindRecord{
UserID: user.ID,
Stage: stage,
RemindTime: time.Now(),
Message: message,
IsShown: false,
}
// 保存提醒记录
m.remindHistory[user.ID] = append(m.remindHistory[user.ID], record)
user.LastRemind[stage] = time.Now()
return record, nil
}
// 请求提醒处理
func (m *RemindStrategyManager) HandleRequestRemind(user *User) (*RemindRecord, error) {
stage := m.getCurrentStage()
if !m.shouldRemindUser(user, stage, "所有请求") {
return nil, nil
}
// 检查业务阻塞
if err := m.checkBusinessBlock(stage); err != nil {
return nil, err
}
message := m.generateMessage(stage, user)
record := &RemindRecord{
UserID: user.ID,
Stage: stage,
RemindTime: time.Now(),
Message: message,
IsShown: false,
}
return record, nil
}
5. 使用示例
func main() {
// 初始化许可证信息
expireTime := time.Now().AddDate(0, 0, 45) // 45天后到期
license := &License{
ExpireTime: expireTime,
IsValid: true,
LicenseType: "企业版",
}
// 创建策略管理器
strategyManager := NewRemindStrategyManager(license)
// 模拟用户登录
adminUser := &User{
ID: "user001",
Username: "admin",
Role: RolePlatformAdmin,
LastRemind: make(map[RemindStage]time.Time),
}
// 处理登录提醒
record, err := strategyManager.HandleLoginRemind(adminUser)
if err != nil {
fmt.Printf("业务阻塞: %v\n", err)
return
}
if record != nil {
fmt.Printf("提醒消息: %s\n", record.Message)
fmt.Printf("提醒阶段: %v\n", record.Stage)
fmt.Printf("提醒时间: %s\n", record.RemindTime.Format("2006-01-02 15:04:05"))
}
// 模拟普通用户请求
normalUser := &User{
ID: "user002",
Username: "user1",
Role: RoleNormalUser,
LastRemind: make(map[RemindStage]time.Time),
}
// 处理请求提醒(在到期后阶段)
requestRecord, err := strategyManager.HandleRequestRemind(normalUser)
if err != nil {
fmt.Printf("请求被阻塞: %v\n", err)
return
}
if requestRecord != nil {
fmt.Printf("请求提醒: %s\n", requestRecord.Message)
}
}
系统架构建议
1. 存储设计
- 使用Redis缓存用户最近提醒记录
- 使用MySQL持久化提醒历史
- 许可证信息配置在配置中心
2. 性能优化
- 使用本地缓存减少数据库查询
- 异步记录提醒日志
- 批量处理用户提醒
3. 扩展性考虑
- 支持动态策略配置
- 可插拔的提醒渠道(邮件、短信、站内信)
- 多租户隔离支持
这个实现方案完整覆盖了需求中的所有策略阶段,提供了灵活的配置方式和良好的扩展性,可以直接集成到现有的微服务架构中。