107 lines
2.7 KiB
Go
107 lines
2.7 KiB
Go
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)
|
|
}
|