package serial import ( "electricity_bill_calc/config" "electricity_bill_calc/global" "electricity_bill_calc/logger" "electricity_bill_calc/tools/time" "fmt" stdTime "time" "github.com/rueian/rueidis" "github.com/samber/lo" "go.uber.org/zap" ) var log = logger.Named("Algorithm", "Unique Serial") // 在防止服务器时间回拨的情况下,生成一个用于生成唯一编号的精简时间戳,该时间戳的起始时间为`2022-02-22 22:22:22.000000 +0800`,时间戳精确到秒。 func generateTimestamp() int64 { for { timestamp := time.Timestamp() cmds := make(rueidis.Commands, 0, 2) cmds = append(cmds, global.Rd.B().Set().Key("LAST_TIMESTAMP").Value(fmt.Sprintf("%d", timestamp)).Nx().ExSeconds(1).Build()) cmds = append(cmds, global.Rd.B().Get().Key("LAST_TIMESTAMP").Build()) results := global.Rd.DoMulti(global.Ctx, cmds...) store_res, err := lo.Last(results) if err != nil { log.Error("从Redis缓存中获取上一次的时间戳失败。", zap.Error(err)) stdTime.Sleep(1 * stdTime.Second) continue } if stored_timestamp, err := store_res.AsInt64(); err == nil && timestamp >= stored_timestamp { return timestamp } else { log.Error("转换从Redis缓存中获取的时间戳失败。", zap.Error(err)) stdTime.Sleep(1 * stdTime.Second) continue } } } // 生成一个基于精简改进的雪花算法的数字类型唯一编号。 func GenerateUniqueSerial() int64 { for { timestamp := generateTimestamp() cmds := make(rueidis.Commands, 0, 2) cmds = append(cmds, global.Rd.B().Set().Key("SERIAL").Value(fmt.Sprintf("%d", 0)).Nx().ExSeconds(1).Build()) cmds = append(cmds, global.Rd.B().Incr().Key("SERIAL").Build()) results := global.Rd.DoMulti(global.Ctx, cmds...) store_res, err := lo.Last(results) if err != nil { log.Error("从Redis缓存中获取上一次的序列号失败。", zap.Error(err)) stdTime.Sleep(1 * stdTime.Second) continue } if stored_serial, err := store_res.AsInt64(); err == nil { return (timestamp << 20) | ((config.ServiceSettings.HostSerial & 0xffff) << 16) | (stored_serial & 0xffff_ffff) } else { log.Error("转换从Redis缓存中获取的序列号失败。", zap.Error(err)) stdTime.Sleep(1 * stdTime.Second) continue } } } // 生成一个基于精简改进的雪花算法的字符串类型唯一编号。 func GenerateUniqueSerialString() string { uniqueId := GenerateUniqueSerial() return fmt.Sprintf("%d", uniqueId) } // 生成一个带有前缀的基于精简改进的雪花算法的字符串类型唯一编号。 func GeneratePrefixedUniqueSerialString(prefix string) string { uniqueId := GenerateUniqueSerial() return fmt.Sprintf("%s%d", prefix, uniqueId) }