chore: 初始开源发布
iotlcm-worker-svr:异步执行中枢(RabbitMQ 消费者 + 全量同步编排)。 - Go module:iotlcm-worker-svr → git.5iot.com/iotlcm-public/iotlcm-worker-svr(214 文件) - 凭据与内部标识脱敏:MySQL/Redis 凭据、私网与生产 IP、内网域名、 库名 xiujie_admin → iotlcm、哨兵名占位 - 159 处真实手机号 → 合法 11 位编造号(保留号段与后 4 位,维持互异, 不破坏「校验 MSISDN 格式」等测试断言) - 移除内部资产:CI 触发器、Jenkins 触发测试文档、预演门禁与镜像 digest 记录 - Dockerfile 改用公共基础镜像(golang:1.25-alpine → alpine:3.23), 移除写死的 git 凭据 - README 重写(架构/全量同步模型/配置/已知失败),补 Apache-2.0 LICENSE,LF 行尾 + .gitattributes 已知:3 个测试包在源仓同一提交上同样失败(client/upstream、 service/allocate、service/inbound),属既有缺陷,本仓未引入亦未修复。
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
package imei
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gvar"
|
||||
"github.com/gogf/gf/v2/database/gredis"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
goredis "github.com/redis/go-redis/v9"
|
||||
"github.com/redis/go-redis/v9/maintnotifications"
|
||||
|
||||
queue "git.5iot.com/iotlcm-public/iotlcm-worker-svr/internal/queue/zset"
|
||||
)
|
||||
|
||||
type leaseClientFactory func() (queue.RedisClient, func() error, error)
|
||||
|
||||
// A custom client must explicitly supply the same bounded-I/O contract. There
|
||||
// is no fallback to context cancellation on an unknown Redis implementation.
|
||||
type boundedLeaseProvider interface {
|
||||
newBoundedLeaseClient(time.Duration) (queue.RedisClient, func() error, error)
|
||||
}
|
||||
|
||||
func newLeaseClientFactory(client queue.RedisClient, config *gredis.Config, budget time.Duration) (leaseClientFactory, error) {
|
||||
if budget <= 0 {
|
||||
return nil, gerror.New("IMEI lease I/O budget must be positive")
|
||||
}
|
||||
if provider, ok := client.(boundedLeaseProvider); ok {
|
||||
return func() (queue.RedisClient, func() error, error) { return provider.newBoundedLeaseClient(budget) }, nil
|
||||
}
|
||||
getter, ok := client.(interface{ GetAdapter() gredis.Adapter })
|
||||
if !ok || getter.GetAdapter() == nil {
|
||||
return nil, gerror.New("IMEI producer requires a bounded GoFrame Redis adapter")
|
||||
}
|
||||
raw, ok := getter.GetAdapter().Client().(*goredis.Client)
|
||||
if !ok {
|
||||
return nil, gerror.New("IMEI producer does not support Redis Cluster or an unknown Redis adapter")
|
||||
}
|
||||
opts := *raw.Options()
|
||||
if opts.Addr == "FailoverClient" {
|
||||
if config == nil || config.MasterName == "" || config.Cluster || config.SlaveOnly {
|
||||
return nil, gerror.New("IMEI Sentinel lease client requires its master configuration")
|
||||
}
|
||||
// Rebuild Sentinel discovery too: sharing the old dialer would retain
|
||||
// its unbounded Sentinel socket reads even if master I/O were bounded.
|
||||
cfg := *config
|
||||
return func() (queue.RedisClient, func() error, error) {
|
||||
client := goredis.NewFailoverClient(&goredis.FailoverOptions{
|
||||
MasterName: cfg.MasterName, SentinelAddrs: sentinelAddresses(cfg.Address),
|
||||
SentinelUsername: cfg.SentinelUser, SentinelPassword: cfg.SentinelPass,
|
||||
Username: cfg.User, Password: cfg.Pass, DB: cfg.Db, Protocol: cfg.Protocol,
|
||||
TLSConfig: opts.TLSConfig,
|
||||
DialTimeout: budget, ReadTimeout: budget, WriteTimeout: budget, PoolTimeout: budget,
|
||||
ContextTimeoutEnabled: true, MaxRetries: -1, DialerRetries: 1,
|
||||
PoolSize: 1, MaxActiveConns: 1,
|
||||
})
|
||||
return &leaseRedis{client}, client.Close, nil
|
||||
}, nil
|
||||
}
|
||||
// Own a separate pool so a timeout/close never closes a consumer's socket.
|
||||
opts.DialTimeout, opts.ReadTimeout, opts.WriteTimeout, opts.PoolTimeout = budget, budget, budget, budget
|
||||
opts.ContextTimeoutEnabled = true
|
||||
// Maintenance handoffs can relax socket deadlines; leases must never do so.
|
||||
opts.MaintNotificationsConfig = &maintnotifications.Config{Mode: maintnotifications.ModeDisabled}
|
||||
opts.MaxRetries, opts.DialerRetries = -1, 1
|
||||
opts.PoolSize, opts.MaxActiveConns, opts.MinIdleConns, opts.MaxIdleConns = 1, 1, 0, 1
|
||||
opts.Dialer = goredis.NewDialer(&opts)
|
||||
return func() (queue.RedisClient, func() error, error) {
|
||||
client := goredis.NewClient(&opts)
|
||||
return &leaseRedis{client}, client.Close, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
func sentinelAddresses(address string) []string {
|
||||
var addresses []string
|
||||
for _, addr := range strings.Split(address, ",") {
|
||||
if addr = strings.TrimSpace(addr); addr != "" {
|
||||
addresses = append(addresses, addr)
|
||||
}
|
||||
}
|
||||
return addresses
|
||||
}
|
||||
|
||||
type leaseRedis struct{ client *goredis.Client }
|
||||
|
||||
func (r *leaseRedis) Do(ctx context.Context, command string, args ...any) (*gvar.Var, error) {
|
||||
result, err := r.client.Do(ctx, append([]any{command}, args...)...).Result()
|
||||
return gvar.New(result), err
|
||||
}
|
||||
|
||||
func (r *leaseRedis) Eval(ctx context.Context, script string, _ int64, keys []string, args []any) (*gvar.Var, error) {
|
||||
result, err := r.client.Eval(ctx, script, keys, args...).Result()
|
||||
return gvar.New(result), err
|
||||
}
|
||||
Reference in New Issue
Block a user