Files
bj_power/bj_power_mes/internal/processor/recipe_loader.go
T

107 lines
2.7 KiB
Go
Raw Normal View History

package processor
import (
"context"
"fmt"
"log/slog"
"sync"
"bj_power_mes/constants"
"bj_power_mes/ent"
"bj_power_mes/ent/recipestep"
)
// RecipeLoader 工艺路线加载器(按 productTypeId 缓存)
type RecipeLoader struct {
client *ent.Client
cache map[int]*RecipeRuntime // productTypeId → RecipeRuntime
mu sync.RWMutex
}
// NewRecipeLoader 创建加载器
func NewRecipeLoader(client *ent.Client) *RecipeLoader {
return &RecipeLoader{
client: client,
cache: make(map[int]*RecipeRuntime),
}
}
// Load 按 productTypeId 加载工艺路线
func (rl *RecipeLoader) Load(ctx context.Context, productTypeID int) (*RecipeRuntime, error) {
rl.mu.RLock()
if rr, ok := rl.cache[productTypeID]; ok {
rl.mu.RUnlock()
return rr, nil
}
rl.mu.RUnlock()
// 查询 productType 关联的 recipe
pt, err := rl.client.ProductType.Get(ctx, productTypeID)
if err != nil {
return nil, fmt.Errorf("get product type %d: %w", productTypeID, err)
}
recipeID := pt.RecipeId
if recipeID == nil || *recipeID == 0 {
return nil, fmt.Errorf("product type %d has no recipe", productTypeID)
}
// 查询 recipe + steps
r, err := rl.client.Recipe.Get(ctx, *recipeID)
if err != nil {
return nil, fmt.Errorf("get recipe %d: %w", recipeID, err)
}
steps, err := r.QuerySteps().
Order(ent.Asc(recipestep.FieldStepIndex)).
All(ctx)
if err != nil {
return nil, fmt.Errorf("query recipe %d steps: %w", recipeID, err)
}
// 构建 RecipeRuntime
stepRuntimes := make([]StepRuntime, 0, len(steps))
for _, s := range steps {
sr := StepRuntime{
StepID: s.ID,
StepIdStr: s.StepId,
StepIndex: s.StepIndex,
StepName: s.StepName,
StepType: constants.StepType(s.StepType),
ResourceType: s.ResourceType,
ToolType: s.ToolType,
AllowedResources: s.AllowedResources,
ProcessingParams: s.ProcessingParams,
NextStepDefault: s.NextStepDefault,
RestoreStep: s.RestoreStep,
StepTimeout: s.StepTimeout,
}
if s.NextStepBranches != nil {
sr.NextStepBranches = make(map[string]string, len(s.NextStepBranches))
for k, v := range s.NextStepBranches {
if vs, ok := v.(string); ok {
sr.NextStepBranches[k] = vs
}
}
}
stepRuntimes = append(stepRuntimes, sr)
}
rr := NewRecipeRuntime(r.ID, r.Code, stepRuntimes)
// 缓存
rl.mu.Lock()
rl.cache[productTypeID] = rr
rl.mu.Unlock()
slog.Info("recipe loader: loaded", "productTypeId", productTypeID, "recipeId", *recipeID, "steps", len(stepRuntimes))
return rr, nil
}
// Invalidate 使缓存失效
func (rl *RecipeLoader) Invalidate(productTypeID int) {
rl.mu.Lock()
defer rl.mu.Unlock()
delete(rl.cache, productTypeID)
}