Files
bj_power/bj_power_mes/internal/logic/logic.go
T
SunYF b6799c9de4 feat: 完成产线与仓储系统多模块迭代升级
本次迭代覆盖MES与WMS核心业务:
1. 新增接驳台托盘传感器读取与AGV对接能力
2. 完善工单排产、备料流程与权限体系拆分
3. 优化看板接口与前端路由、样式
4. 新增操作日志、库存盘点与角色保护逻辑
5. 修复代理地址、BOM保存等已知问题
2026-09-04 14:18:53 +08:00

95 lines
2.3 KiB
Go

package logic
import (
"context"
"encoding/json"
"time"
"bj_power_mes/internal/svc"
)
// Service 业务逻辑服务(handler 薄层调用)
type Service struct {
ctx *svc.ServiceContext
}
func New(s *svc.ServiceContext) *Service {
return &Service{ctx: s}
}
// cachedTyped 泛型版缓存:与 cached 同为 TTL + SETNX 防击穿,
// 区别是返回强类型,调用方不必再做类型断言(看板快照等结构化数据用这个)。
func cachedTyped[T any](ctx context.Context, s *Service, key string, ttl int, build func() (T, error)) (T, error) {
if s.ctx.RedisClient == nil {
return build()
}
if v, err := s.ctx.RedisClient.Get(key); err == nil && v != "" {
var out T
if json.Unmarshal([]byte(v), &out) == nil {
return out, nil
}
}
lockKey := key + ":lock"
ok, _ := s.ctx.RedisClient.SetnxEx(lockKey, "1", 10)
if !ok {
for i := 0; i < 10; i++ {
time.Sleep(100 * time.Millisecond)
if v, err := s.ctx.RedisClient.Get(key); err == nil && v != "" {
var out T
if json.Unmarshal([]byte(v), &out) == nil {
return out, nil
}
}
}
return build()
}
defer func() { _, _ = s.ctx.RedisClient.Del(lockKey) }()
data, err := build()
if err == nil {
if b, e := json.Marshal(data); e == nil {
_ = s.ctx.RedisClient.Setex(key, string(b), ttl)
}
}
return data, err
}
// cached 看板缓存:TTL + 防击穿(SETNX 锁),同一 key 同时仅一个打到 DB
func (s *Service) cached(ctx context.Context, key string, ttl int, build func() (any, error)) (any, error) {
if s.ctx.RedisClient == nil {
return build()
}
if v, err := s.ctx.RedisClient.Get(key); err == nil && v != "" {
var out any
if json.Unmarshal([]byte(v), &out) == nil {
return out, nil
}
}
lockKey := key + ":lock"
ok, _ := s.ctx.RedisClient.SetnxEx(lockKey, "1", 10)
if !ok {
// 有人正在重建缓存:短暂等待后重读
for i := 0; i < 10; i++ {
time.Sleep(100 * time.Millisecond)
if v, err := s.ctx.RedisClient.Get(key); err == nil && v != "" {
var out any
if json.Unmarshal([]byte(v), &out) == nil {
return out, nil
}
}
}
return build()
}
defer func() { _, _ = s.ctx.RedisClient.Del(lockKey) }()
data, err := build()
if err == nil {
if b, e := json.Marshal(data); e == nil {
_ = s.ctx.RedisClient.Setex(key, string(b), ttl)
}
}
return data, err
}