mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-06 07:36:37 +08:00
fix(idgen): retry snowflake generation and error on negative ID
NextUint64ID now retries up to 3 times when Int64() is negative, then returns an error instead of 0 or Fatalf. All call sites propagate the error to avoid GORM omitting zero-value primary keys.
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
package idgen
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/Rain-kl/Wavelet/internal/config"
|
||||
@@ -15,6 +17,11 @@ import (
|
||||
// 2025-12-01 00:00:00 UTC 的毫秒时间戳
|
||||
const epoch int64 = 1764547200000
|
||||
|
||||
const maxNegativeIDRetries = 3
|
||||
|
||||
// ErrNegativeSnowflakeID 表示 Snowflake 在重试后仍生成负值 ID。
|
||||
var ErrNegativeSnowflakeID = errors.New("snowflake generated negative ID")
|
||||
|
||||
var node *snowflake.Node
|
||||
|
||||
func init() {
|
||||
@@ -29,11 +36,15 @@ func init() {
|
||||
log.Printf("[Snowflake] initialized with node ID: %d, epoch: 2025-12-01\n", nodeID)
|
||||
}
|
||||
|
||||
// NextUint64ID 生成下一个分布式唯一 ID
|
||||
func NextUint64ID() uint64 {
|
||||
val := node.Generate().Int64()
|
||||
if val < 0 {
|
||||
return 0
|
||||
// NextUint64ID 生成下一个分布式唯一 ID。
|
||||
// 理论上不应出现负值;若出现则最多重试 maxNegativeIDRetries 次,仍失败则返回错误。
|
||||
func NextUint64ID() (uint64, error) {
|
||||
for attempt := 1; attempt <= maxNegativeIDRetries; attempt++ {
|
||||
id := node.Generate().Int64()
|
||||
if id >= 0 {
|
||||
return uint64(id), nil
|
||||
}
|
||||
log.Printf("[Snowflake] generated negative ID: %d (attempt %d/%d)", id, attempt, maxNegativeIDRetries)
|
||||
}
|
||||
return uint64(val)
|
||||
}
|
||||
return 0, fmt.Errorf("%w: failed after %d attempts", ErrNegativeSnowflakeID, maxNegativeIDRetries)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2026 Arctel.net
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package idgen
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNextUint64ID(t *testing.T) {
|
||||
id, err := NextUint64ID()
|
||||
require.NoError(t, err)
|
||||
assert.NotZero(t, id)
|
||||
}
|
||||
Reference in New Issue
Block a user