github.com/wfusion/gofusion@v1.1.14/async/construct.go (about) 1 package async 2 3 import ( 4 "context" 5 "log" 6 "sync" 7 "syscall" 8 9 "github.com/pkg/errors" 10 11 "github.com/wfusion/gofusion/common/di" 12 "github.com/wfusion/gofusion/common/utils" 13 "github.com/wfusion/gofusion/config" 14 15 _ "github.com/wfusion/gofusion/log/customlogger" 16 ) 17 18 var ( 19 locker sync.RWMutex 20 consumers = map[string]map[string]Consumable{} 21 producers = map[string]map[string]Producable{} 22 ) 23 24 func Construct(ctx context.Context, confs map[string]*Conf, opts ...utils.OptionExtender) func() { 25 opt := utils.ApplyOptions[config.InitOption](opts...) 26 optU := utils.ApplyOptions[useOption](opts...) 27 if opt.AppName == "" { 28 opt.AppName = optU.appName 29 } 30 31 for name, conf := range confs { 32 addInstance(ctx, name, conf, opt) 33 } 34 return func() { 35 locker.Lock() 36 defer locker.Unlock() 37 38 pid := syscall.Getpid() 39 app := config.Use(opt.AppName).AppName() 40 if consumers != nil { 41 for name, router := range consumers[opt.AppName] { 42 log.Printf("%v [Gofusion] %s %s %s exiting...", pid, app, config.ComponentAsync, name) 43 if err := router.shutdown(); err == nil { 44 log.Printf("%v [Gofusion] %s %s %s exited", pid, app, config.ComponentAsync, name) 45 } else { 46 log.Printf("%v [Gofusion] %s %s %s exit failed: %s", pid, app, config.ComponentAsync, name, err) 47 } 48 } 49 delete(consumers, opt.AppName) 50 } 51 52 if producers != nil { 53 producers[opt.AppName] = make(map[string]Producable, len(producers)) 54 } 55 } 56 } 57 58 func addInstance(ctx context.Context, name string, conf *Conf, opt *config.InitOption) { 59 var ( 60 producer Producable 61 consumer Consumable 62 ) 63 switch conf.Type { 64 case asyncTypeAsynq: 65 if conf.Producer { 66 producer = newAsynqProducer(ctx, opt.AppName, name, conf) 67 } 68 if conf.Consumer { 69 consumer = newAsynqConsumer(ctx, opt.AppName, name, conf) 70 } 71 case asyncTypeMysql: 72 fallthrough 73 default: 74 panic(ErrUnsupportedSchedulerType) 75 } 76 77 locker.Lock() 78 defer locker.Unlock() 79 if consumer != nil { 80 if consumers == nil { 81 consumers = make(map[string]map[string]Consumable) 82 } 83 if consumers[opt.AppName] == nil { 84 consumers[opt.AppName] = make(map[string]Consumable) 85 } 86 if _, ok := consumers[name]; ok { 87 panic(ErrDuplicatedInstanceName) 88 } 89 consumers[opt.AppName][name] = consumer 90 91 // ioc 92 if opt.DI != nil { 93 opt.DI.MustProvide( 94 func() Consumable { return C(name, AppName(opt.AppName)) }, 95 di.Name(name), 96 ) 97 } 98 } 99 100 if producer != nil { 101 if producers == nil { 102 producers = make(map[string]map[string]Producable) 103 } 104 if producers[opt.AppName] == nil { 105 producers[opt.AppName] = make(map[string]Producable) 106 } 107 if _, ok := producers[name]; ok { 108 panic(ErrDuplicatedInstanceName) 109 } 110 producers[opt.AppName][name] = producer 111 112 // ioc 113 if opt.DI != nil { 114 opt.DI.MustProvide( 115 func() Producable { return P(name) }, 116 di.Name(name), 117 ) 118 } 119 } 120 } 121 122 type useOption struct { 123 appName string 124 } 125 126 func AppName(name string) utils.OptionFunc[useOption] { 127 return func(o *useOption) { 128 o.appName = name 129 } 130 } 131 132 func C(name string, opts ...utils.OptionExtender) Consumable { 133 opt := utils.ApplyOptions[useOption](opts...) 134 135 locker.RLock() 136 defer locker.RUnlock() 137 consumers, ok := consumers[opt.appName] 138 if !ok { 139 panic(errors.Errorf("async consumer instance not found for app: %s", opt.appName)) 140 } 141 consumer, ok := consumers[name] 142 if !ok { 143 panic(errors.Errorf("async consumer instance not found for name: %s", name)) 144 } 145 return consumer 146 } 147 148 func P(name string, opts ...utils.OptionExtender) Producable { 149 opt := utils.ApplyOptions[useOption](opts...) 150 151 locker.RLock() 152 defer locker.RUnlock() 153 producers, ok := producers[opt.appName] 154 if !ok { 155 panic(errors.Errorf("async producer instance not found for app: %s", opt.appName)) 156 } 157 producer, ok := producers[name] 158 if !ok { 159 panic(errors.Errorf("async producer instance not found for name: %s", name)) 160 } 161 return producer 162 } 163 164 func init() { 165 config.AddComponent(config.ComponentAsync, Construct, config.WithFlag(&flagString)) 166 }