From 2b3048141994314dea88d168f5f07aa0144f53b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=B6=9B?= Date: Wed, 31 May 2023 09:38:39 +0800 Subject: [PATCH] =?UTF-8?q?feat(serial):=E5=A2=9E=E5=8A=A0=E6=94=B9?= =?UTF-8?q?=E8=BF=9B=E9=9B=AA=E8=8A=B1=E7=AE=97=E6=B3=95=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/serial/algorithm.go | 76 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 tools/serial/algorithm.go diff --git a/tools/serial/algorithm.go b/tools/serial/algorithm.go new file mode 100644 index 0000000..9ce2354 --- /dev/null +++ b/tools/serial/algorithm.go @@ -0,0 +1,76 @@ +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) +}