go:Pipeline Pattern

项目结构:

Go 复制代码
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 14:07
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : config.go
*/
package config
 
import (
    "log"
    "os"
    "time"
)
 
const (
    Timeout        = 1 * time.Second
    RetryTimes     = 2
    MaxReworkCount = 2
    ProcessSleep   = 200 * time.Millisecond
)
 
var Logger = log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lmsgprefix)
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 14:08
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : model.go
*/
package model
 
type RawStone struct {
    SN     int
    Carat  float64
    Origin string
}
 
type CutDiamond struct {
    SN          int
    Carat       float64
    CutGrade    string
    ReworkCount int
}
 
type ClarityResult struct {
    SN      int
    Grade   string
    Pass    bool
    Diamond *CutDiamond
}
 
type ColorResult struct {
    SN      int
    Grade   string
    Pass    bool
    Diamond *CutDiamond
}
 
type QCMerged struct {
    SN      int
    Carat   float64
    Cut     string
    Clarity string
    Color   string
    PassAll bool
    Diamond *CutDiamond
}
 
type Inlaid struct {
    SN        int
    Metal     string
    QC        *QCMerged
    LaborCost float64
}
 
type Finished struct {
    SN    int
    Name  string
    Price float64
}
 
type SaleOrder struct {
    SN    int
    Name  string
    Price float64
}
 
type DefectItem struct {
    Item  any
    Stage string
    Err   string
}
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 14:09
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : channel.go
*/
package core
 
import "sync"
 
const StopSignal = "__STOP__"
 
type Channel[T any] struct {
    ch chan T
}
 
func NewChannel[T any]() *Channel[T] {
    return &Channel[T]{ch: make(chan T, 10)}
}
 
func (c *Channel[T]) Send(item T) {
    c.ch <- item
}
 
func (c *Channel[T]) Recv() (T, bool) {
    v, ok := <-c.ch
    return v, ok
}
 
func (c *Channel[T]) Close() {
    close(c.ch)
}
 
func SplitStream[T any](src *Channel[T], dsts []*Channel[T], wg *sync.WaitGroup) {
    defer wg.Done()
    for {
        item, ok := src.Recv()
        if !ok {
            for _, d := range dsts {
                d.Close()
            }
            return
        }
        for _, d := range dsts {
            d.Send(item)
        }
    }
}
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 16:39
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : metrics.go
*/
package core
 
import "sync"
 
type Metrics struct {
    Total   int
    Success int
    Fail    int
    Retry   int
}
 
var (
    stageMetrics = make(map[string]*Metrics)
    mu           sync.RWMutex
)
 
func InitStage(name string) {
    mu.Lock()
    defer mu.Unlock()
    if stageMetrics[name] == nil {
        stageMetrics[name] = &Metrics{}
    }
}
 
func IncTotal(name string) {
    mu.Lock()
    defer mu.Unlock()
    stageMetrics[name].Total++
}
 
func IncSuccess(name string) {
    mu.Lock()
    defer mu.Unlock()
    stageMetrics[name].Success++
}
 
func IncFail(name string) {
    mu.Lock()
    defer mu.Unlock()
    stageMetrics[name].Fail++
}
 
func IncRetry(name string) {
    mu.Lock()
    defer mu.Unlock()
    stageMetrics[name].Retry++
}
 
func GetMetrics() map[string]*Metrics {
    mu.RLock()
    defer mu.RUnlock()
    copy := make(map[string]*Metrics)
    for k, v := range stageMetrics {
        copy[k] = v
    }
    return copy
}
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 16:40
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : stage.go
*/
package core
 
import (
    "godesginpattern/pipeline/config"
    "godesginpattern/pipeline/model"
    "time"
)
 
func RunStage[Tin, Tout any](
    name string,
    in *Channel[Tin],
    out *Channel[Tout],
    defect *Channel[*model.DefectItem],
    process func(Tin) (Tout, error),
) {
    config.Logger.Printf("【阶段启动】%s", name)
    InitStage(name)
 
    for {
        item, ok := in.Recv()
        if !ok {
            break
        }
 
        IncTotal(name)
        var res Tout
        var err error
        success := false
 
        for attempt := 0; attempt <= config.RetryTimes; attempt++ {
            res, err = process(item)
            if err == nil {
                success = true
                break
            }
            IncRetry(name)
            sn := getSN(item)
            config.Logger.Printf("【%s】SN:%d 第%d次失败: %v", name, sn, attempt+1, err)
            time.Sleep(100 * time.Millisecond)
        }
 
        if success {
            IncSuccess(name)
            out.Send(res)
        } else {
            IncFail(name)
            defect.Send(&model.DefectItem{
                Item:  item,
                Stage: name,
                Err:   err.Error(),
            })
        }
    }
 
    out.Close()
    config.Logger.Printf("【阶段结束】%s", name)
}
 
func getSN(v any) int {
    switch t := v.(type) {
    case *model.CutDiamond:
        return t.SN
    case *model.QCMerged:
        return t.SN
    case *model.Inlaid:
        return t.SN
    case *model.Finished:
        return t.SN
    default:
        return 0
    }
}
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 16:42
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : fork_join.go
*/
package core
 
import (
    "godesginpattern/pipeline/model"
    "sync"
)
 
func ForkBranch[Tin, Tout any](
    in *Channel[Tin],
    out *Channel[Tout],
    fn func(Tin) Tout,
    wg *sync.WaitGroup,
) {
    defer wg.Done()
    for {
        item, ok := in.Recv()
        if !ok {
            break
        }
        out.Send(fn(item))
    }
    out.Close()
}
 
func JoinMerger(
    clarityCh *Channel[*model.ClarityResult],
    colorCh *Channel[*model.ColorResult],
    out *Channel[*model.QCMerged],
    merge func(*model.CutDiamond, *model.ClarityResult, *model.ColorResult) *model.QCMerged,
) {
    clarityMap := make(map[int]*model.ClarityResult)
    colorMap := make(map[int]*model.ColorResult)
 
    var wg sync.WaitGroup
    wg.Add(2)
 
    go func() {
        defer wg.Done()
        for {
            r, ok := clarityCh.Recv()
            if !ok {
                break
            }
            clarityMap[r.SN] = r
        }
    }()
 
    go func() {
        defer wg.Done()
        for {
            r, ok := colorCh.Recv()
            if !ok {
                break
            }
            colorMap[r.SN] = r
        }
    }()
 
    wg.Wait()
 
    for sn, cr := range clarityMap {
        if cc, ok := colorMap[sn]; ok {
            out.Send(merge(cr.Diamond, cr, cc))
        }
    }
    out.Close()
}
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 16:43
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : defect.go
*/
package core
 
import (
    "godesginpattern/pipeline/config"
    "godesginpattern/pipeline/model"
)
 
func DefectReworkConsumer(
    defectCh *Channel[*model.DefectItem],
    reworkCh *Channel[*model.CutDiamond],
) {
    config.Logger.Println("次品返工分拣中心启动")
    for {
        item, ok := defectCh.Recv()
        if !ok {
            break
        }
 
        diamond, ok := item.Item.(*model.CutDiamond)
        if !ok {
            continue
        }
 
        if diamond.ReworkCount < config.MaxReworkCount {
            diamond.ReworkCount++
            config.Logger.Printf("【返工】SN:%d 第%d次回流切割工序", diamond.SN, diamond.ReworkCount)
            reworkCh.Send(diamond)
        } else {
            config.Logger.Printf("【报废】SN:%d 超过最大返工次数", diamond.SN)
        }
    }
    reworkCh.Close()
}
Go 复制代码
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 16:45
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : services.go
*/
package service
 
import (
    "errors"
    "godesginpattern/pipeline/config"
    "godesginpattern/pipeline/model"
    "math/rand"
    "strconv"
    "time"
)
 
func CutStone(raw *model.RawStone) (*model.CutDiamond, error) {
    time.Sleep(config.ProcessSleep)
    grade := "VG"
    if raw.Carat >= 1.0 {
        grade = "EX"
    }
    return &model.CutDiamond{
        SN:       raw.SN,
        Carat:    raw.Carat,
        CutGrade: grade,
    }, nil
}
 
func CheckClarity(d *model.CutDiamond) *model.ClarityResult {
    time.Sleep(config.ProcessSleep)
    grades := []string{"VS1", "VS2", "SI1"}
    g := grades[rand.Intn(len(grades))]
    pass := g != "SI1" || d.Carat > 0.7
    return &model.ClarityResult{
        SN:      d.SN,
        Grade:   g,
        Pass:    pass,
        Diamond: d,
    }
}
 
func CheckColor(d *model.CutDiamond) *model.ColorResult {
    time.Sleep(config.ProcessSleep)
    grades := []string{"D", "G", "J"}
    g := grades[rand.Intn(len(grades))]
    pass := g == "D" || g == "G"
    return &model.ColorResult{
        SN:      d.SN,
        Grade:   g,
        Pass:    pass,
        Diamond: d,
    }
}
 
func MergeQC(d *model.CutDiamond, c *model.ClarityResult, co *model.ColorResult) *model.QCMerged {
    return &model.QCMerged{
        SN:      d.SN,
        Carat:   d.Carat,
        Cut:     d.CutGrade,
        Clarity: c.Grade,
        Color:   co.Grade,
        PassAll: c.Pass && co.Pass,
        Diamond: d,
    }
}
 
func Inlay(qc *model.QCMerged) (*model.Inlaid, error) {
    time.Sleep(config.ProcessSleep)
    if !qc.PassAll {
        return nil, errors.New("钻石质检未通过,禁止镶嵌加工")
    }
    metals := []string{"18K黄金", "PT950铂金", "S925银"}
    metal := metals[rand.Intn(len(metals))]
    return &model.Inlaid{
        SN:        qc.SN,
        Metal:     metal,
        QC:        qc,
        LaborCost: qc.Carat * 1200,
    }, nil
}
 
func Finish(in *model.Inlaid) (*model.Finished, error) {
    time.Sleep(config.ProcessSleep)
    cost := in.LaborCost + in.QC.Carat*8500
    price := cost * 1.75
    name := in.Metal + "钻戒-" + strconv.Itoa(in.SN)
    return &model.Finished{
        SN:    in.SN,
        Name:  name,
        Price: price,
    }, nil
}
 
func Sale(f *model.Finished) (*model.SaleOrder, error) {
    time.Sleep(config.ProcessSleep / 2)
    return &model.SaleOrder{
        SN:    f.SN,
        Name:  f.Name,
        Price: f.Price,
    }, nil
}
 
 
 
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 16:45
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : factory.go
*/
package factory
 
import (
    "godesginpattern/pipeline/core"
    "godesginpattern/pipeline/model"
    "godesginpattern/pipeline/service"
    "sync"
)
 
func BuildPipeline(
    source *core.Channel[*model.RawStone], // 修复:输入改为 RawStone
) (*core.Channel[*model.SaleOrder], *sync.WaitGroup) {
 
    // 所有通道类型对齐
    rawIn := source
    cutOut := core.NewChannel[*model.CutDiamond]()
 
    clarityIn := core.NewChannel[*model.CutDiamond]()
    colorIn := core.NewChannel[*model.CutDiamond]()
    clarityOut := core.NewChannel[*model.ClarityResult]()
    colorOut := core.NewChannel[*model.ColorResult]()
 
    mergedOut := core.NewChannel[*model.QCMerged]()
    inlayOut := core.NewChannel[*model.Inlaid]()
    finishOut := core.NewChannel[*model.Finished]()
    saleOut := core.NewChannel[*model.SaleOrder]()
    defectCh := core.NewChannel[*model.DefectItem]()
 
    var wg sync.WaitGroup
    wg.Add(3)
 
    // 分流器:切割完成 → 分发给净度/颜色检测
    go core.SplitStream(cutOut, []*core.Channel[*model.CutDiamond]{clarityIn, colorIn}, &wg)
 
    // 并行质检分支
    go core.ForkBranch(clarityIn, clarityOut, service.CheckClarity, &wg)
    go core.ForkBranch(colorIn, colorOut, service.CheckColor, &wg)
 
    // 合并两路质检结果
    go core.JoinMerger(clarityOut, colorOut, mergedOut, service.MergeQC)
 
    // 流水线所有工序(类型 100% 匹配)
    go core.RunStage("1-原石切割", rawIn, cutOut, defectCh, service.CutStone)
    go core.RunStage("2-贵金属镶嵌", mergedOut, inlayOut, defectCh, service.Inlay)
    go core.RunStage("3-成品定价", inlayOut, finishOut, defectCh, service.Finish)
    go core.RunStage("4-销售出库", finishOut, saleOut, defectCh, service.Sale)
 
    // 次品返工
    go core.DefectReworkConsumer(defectCh, cutOut)
 
    return saleOut, &wg
}

调用:

Go 复制代码
/*
# 版权所有  2026 ©涂聚文有限公司™ ®
# 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
# 描述:Pipeline Pattern 管道模式
# Author    : geovindu,Geovin Du 涂聚文.
# IDE       : goLang 2024.3.6 go 26.2
# os        : windows 10
# database  : mysql 9.0 sql server 2019, postgreSQL 17.0  Oracle 21c Neo4j
# Datetime  : 2026/6/21 16:47
# User      :  geovindu
# Product   : GoLand
# Project   : godesginpattern
# File      : pipelinebll.go
*/
package bll
 
import (
    "godesginpattern/pipeline/config"
    "godesginpattern/pipeline/core"
    "godesginpattern/pipeline/factory"
    "godesginpattern/pipeline/model"
)
 
func PipelineMain() {
    config.Logger.Println("===== 企业级珠宝异步Pipeline启动(并行质检+次品返工)=====")
 
    // 输入通道:RawStone 原石(完全对齐)
    source := core.NewChannel[*model.RawStone]()
 
    raws := []*model.RawStone{
        {SN: 2001, Carat: 0.62, Origin: "南非"},
        {SN: 2002, Carat: 1.15, Origin: "博茨瓦纳"},
        {SN: 2003, Carat: 0.48, Origin: "俄罗斯"},
        {SN: 2004, Carat: 1.32, Origin: "南非"},
        {SN: 2005, Carat: 0.75, Origin: "澳大利亚"},
        {SN: 2007, Carat: 0.90, Origin: "纳米比亚"},
    }
 
    // 直接投放原石,不再提前切割
    for _, r := range raws {
        config.Logger.Printf("原料进料 SN:%d", r.SN)
        source.Send(r)
    }
    source.Close()
 
    // 启动流水线
    saleOut, wg := factory.BuildPipeline(source)
 
    // 消费销售结果
    count := 0
    for {
        order, ok := saleOut.Recv()
        if !ok {
            break
        }
        count++
        config.Logger.Printf("✅ 销售单据 SN:%d 售价:%.2f", order.SN, order.Price)
    }
 
    wg.Wait()
    config.Logger.Println("\n========== 流水线执行完成 ==========")
    config.Logger.Printf("总投入原石:%d件  成功销售:%d件", len(raws), count)
}
  

输出: