package main
import ( "context" "errors" "fmt" "net/http" "reflect" "sync" "time" )
var ( ErrConcurrencyComponentTimeout = errors.New("Concurrency Component Timeout") )
type Context struct { TimeoutCtx context.Context context.CancelFunc }
func GetContext(d time.Duration) *Context { c := &Context{} c.TimeoutCtx, c.CancelFunc = context.WithTimeout(context.Background(), d) return c }
type Component interface { Mount(c Component, components ...Component) error Remove(c Component) error Do(ctx *Context, currentConponent Component, wg *sync.WaitGroup) error BusinessLogicDo(resChan chan interface{}) error ChildsDo(ctx *Context) error }
type BaseComponent struct { ChildComponents []Component }
func (bc *BaseComponent) Mount(c Component, components ...Component) (err error) { bc.ChildComponents = append(bc.ChildComponents, c) if len(components) == 0 { return } bc.ChildComponents = append(bc.ChildComponents, components...) return }
func (bc *BaseComponent) Remove(c Component) (err error) { if len(bc.ChildComponents) == 0 { return } for k, childComponent := range bc.ChildComponents { if c == childComponent { fmt.Println(runFuncName(), "移除:", reflect.TypeOf(childComponent)) bc.ChildComponents = append(bc.ChildComponents[:k], bc.ChildComponents[k+1:]...) } } return }
func (bc *BaseComponent) Do(ctx *Context, currentConponent Component, wg *sync.WaitGroup) (err error) { err = currentConponent.BusinessLogicDo(nil) if err != nil { return err } return currentConponent.ChildsDo(ctx) }
func (bc *BaseComponent) BusinessLogicDo(resChan chan interface{}) (err error) { return }
func (bc *BaseComponent) ChildsDo(ctx *Context) (err error) { for _, childComponent := range bc.ChildComponents { if err = childComponent.Do(ctx, childComponent, nil); err != nil { return err } } return }
type BaseConcurrencyComponent struct { BaseComponent HasChildConcurrencyComponents bool ChildConcurrencyComponents []Component *sync.WaitGroup logicResChan chan interface{} Err error }
func (bc *BaseConcurrencyComponent) Remove(c Component) (err error) { if len(bc.ChildComponents) == 0 { return } for k, childComponent := range bc.ChildComponents { if c == childComponent { fmt.Println(runFuncName(), "移除:", reflect.TypeOf(childComponent)) bc.ChildComponents = append(bc.ChildComponents[:k], bc.ChildComponents[k+1:]...) } } for k, childComponent := range bc.ChildConcurrencyComponents { if c == childComponent { fmt.Println(runFuncName(), "移除:", reflect.TypeOf(childComponent)) bc.ChildConcurrencyComponents = append(bc.ChildComponents[:k], bc.ChildComponents[k+1:]...) } } return }
func (bc *BaseConcurrencyComponent) MountConcurrency(c Component, components ...Component) (err error) { bc.HasChildConcurrencyComponents = true bc.ChildConcurrencyComponents = append(bc.ChildConcurrencyComponents, c) if len(components) == 0 { return } bc.ChildConcurrencyComponents = append(bc.ChildConcurrencyComponents, components...) return }
func (bc *BaseConcurrencyComponent) ChildsDo(ctx *Context) (err error) { if bc.WaitGroup == nil { bc.WaitGroup = &sync.WaitGroup{} } for _, childComponent := range bc.ChildConcurrencyComponents { bc.WaitGroup.Add(1) go childComponent.Do(ctx, childComponent, bc.WaitGroup) } for _, childComponent := range bc.ChildComponents { if err = childComponent.Do(ctx, childComponent, nil); err != nil { return err } } if bc.HasChildConcurrencyComponents { bc.WaitGroup.Wait() } return }
func (bc *BaseConcurrencyComponent) Do(ctx *Context, currentConponent Component, wg *sync.WaitGroup) (err error) { defer wg.Done() if bc.logicResChan == nil { bc.logicResChan = make(chan interface{}, 1) }
go currentConponent.BusinessLogicDo(bc.logicResChan)
select { case <-bc.logicResChan: fmt.Println(runFuncName(), "bc.BusinessLogicDo wait.done...") break case <-ctx.TimeoutCtx.Done(): fmt.Println(runFuncName(), "bc.BusinessLogicDo timeout...") bc.Err = ErrConcurrencyComponentTimeout break } err = currentConponent.ChildsDo(ctx) return }
type CheckoutPageComponent struct { BaseConcurrencyComponent }
func (bc *CheckoutPageComponent) BusinessLogicDo(resChan chan interface{}) (err error) { fmt.Println(runFuncName(), "订单结算页面组件...") return }
type AddressComponent struct { BaseConcurrencyComponent }
func (bc *AddressComponent) BusinessLogicDo(resChan chan interface{}) error { fmt.Println(runFuncName(), "地址组件...") fmt.Println(runFuncName(), "获取地址信息 ing...")
http.Get("http://example.com/")
resChan <- struct{}{} fmt.Println(runFuncName(), "获取地址信息 done...") return nil }
type PayMethodComponent struct { BaseConcurrencyComponent }
func (bc *PayMethodComponent) BusinessLogicDo(resChan chan interface{}) (err error) { fmt.Println(runFuncName(), "支付方式组件...") fmt.Println(runFuncName(), "获取支付方式 ing...") resChan <- struct{}{} fmt.Println(runFuncName(), "获取支付方式 done...") return nil }
type StoreComponent struct { BaseComponent }
func (bc *StoreComponent) BusinessLogicDo(resChan chan interface{}) (err error) { fmt.Println(runFuncName(), "店铺组件...") return }
type SkuComponent struct { BaseComponent }
func (bc *SkuComponent) BusinessLogicDo(resChan chan interface{}) (err error) { fmt.Println(runFuncName(), "商品组件...") return }
type PromotionComponent struct { BaseComponent }
func (bc *PromotionComponent) BusinessLogicDo(resChan chan interface{}) (err error) { fmt.Println(runFuncName(), "优惠信息组件...") return }
type ExpressComponent struct { BaseComponent }
func (bc *ExpressComponent) BusinessLogicDo(resChan chan interface{}) (err error) { fmt.Println(runFuncName(), "物流组件...") return }
type AftersaleComponent struct { BaseComponent }
func (bc *AftersaleComponent) BusinessLogicDo(resChan chan interface{}) (err error) { fmt.Println(runFuncName(), "售后组件...") return }
type InvoiceComponent struct { BaseConcurrencyComponent }
func (bc *InvoiceComponent) BusinessLogicDo(resChan chan interface{}) (err error) { fmt.Println(runFuncName(), "发票组件...") fmt.Println(runFuncName(), "获取发票信息 ing...") resChan <- struct{}{} fmt.Println(runFuncName(), "获取发票信息 done...") return }
type CouponComponent struct { BaseConcurrencyComponent }
func (bc *CouponComponent) BusinessLogicDo(resChan chan interface{}) (err error) { fmt.Println(runFuncName(), "优惠券组件...") fmt.Println(runFuncName(), "获取最优优惠券 ing...")
http.Get("http://example.com/")
resChan <- struct{}{} fmt.Println(runFuncName(), "获取最优优惠券 done...") return }
type GiftCardComponent struct { BaseConcurrencyComponent }
func (bc *GiftCardComponent) BusinessLogicDo(resChan chan interface{}) (err error) { fmt.Println(runFuncName(), "礼品卡组件...") fmt.Println(runFuncName(), "获取礼品卡信息 ing...") resChan <- struct{}{} fmt.Println(runFuncName(), "获取礼品卡信息 done...") return }
type OrderComponent struct { BaseComponent }
func (bc *OrderComponent) BusinessLogicDo(resChan chan interface{}) (err error) { fmt.Println(runFuncName(), "订单金额详细信息组件...") return }
func Demo() { checkoutPage := &CheckoutPageComponent{}
storeComponent := &StoreComponent{} skuComponent := &SkuComponent{} skuComponent.Mount( &PromotionComponent{}, &AftersaleComponent{}, ) storeComponent.Mount( skuComponent, &ExpressComponent{}, )
checkoutPage.Mount( storeComponent, &OrderComponent{}, ) checkoutPage.MountConcurrency( &AddressComponent{}, &PayMethodComponent{}, &InvoiceComponent{}, &CouponComponent{}, &GiftCardComponent{}, )
ctx := GetContext(5 * time.Second) defer ctx.CancelFunc() checkoutPage.ChildsDo(ctx) }
func main() { runtime.GOMAXPROCS(runtime.NumCPU() - 1) DemoConcurrency( }
func runFuncName() string { pc := make([]uintptr, 1) runtime.Callers(2, pc) f := runtime.FuncForPC(pc[0]) return f.Name() return "" }
|