github.com/wfusion/gofusion@v1.1.14/mq/construct.go (about) 1 package mq 2 3 import ( 4 "context" 5 "log" 6 "reflect" 7 "sync" 8 "syscall" 9 10 "github.com/pkg/errors" 11 12 "github.com/wfusion/gofusion/common/di" 13 "github.com/wfusion/gofusion/common/infra/watermill" 14 "github.com/wfusion/gofusion/common/utils" 15 "github.com/wfusion/gofusion/common/utils/inspect" 16 "github.com/wfusion/gofusion/config" 17 18 fusLog "github.com/wfusion/gofusion/log" 19 20 _ "github.com/wfusion/gofusion/log/customlogger" 21 ) 22 23 var ( 24 locker sync.RWMutex 25 subscribers = map[string]map[string]Subscriber{} 26 publishers = map[string]map[string]Publisher{} 27 routers = map[string]map[string]IRouter{} 28 ) 29 30 func Construct(ctx context.Context, confs map[string]*Conf, opts ...utils.OptionExtender) func() { 31 opt := utils.ApplyOptions[config.InitOption](opts...) 32 optU := utils.ApplyOptions[useOption](opts...) 33 if opt.AppName == "" { 34 opt.AppName = optU.appName 35 } 36 37 for name, conf := range confs { 38 addInstance(ctx, name, conf, opt) 39 } 40 41 return func() { 42 locker.Lock() 43 defer locker.Unlock() 44 45 pid := syscall.Getpid() 46 app := config.Use(opt.AppName).AppName() 47 if routers != nil { 48 for name, router := range routers[opt.AppName] { 49 log.Printf("%v [Gofusion] %s %s %s router exiting...", 50 pid, app, config.ComponentMessageQueue, name) 51 if err := router.close(); err == nil { 52 log.Printf("%v [Gofusion] %s %s %s router exited", 53 pid, app, config.ComponentMessageQueue, name) 54 } else { 55 log.Printf("%v [Gofusion] %s %s %s router exit failed: %s", 56 pid, app, config.ComponentMessageQueue, name, err) 57 } 58 } 59 delete(routers, opt.AppName) 60 } 61 62 if publishers != nil { 63 for name, publisher := range publishers[opt.AppName] { 64 log.Printf("%v [Gofusion] %s %s %s publisher exiting...", 65 pid, app, config.ComponentMessageQueue, name) 66 if err := publisher.close(); err == nil { 67 log.Printf("%v [Gofusion] %s %s %s publisher exited", 68 pid, app, config.ComponentMessageQueue, name) 69 } else { 70 log.Printf("%v [Gofusion] %s %s %s publisher exit failed: %s", 71 pid, app, config.ComponentMessageQueue, name, err) 72 } 73 } 74 delete(publishers, opt.AppName) 75 } 76 77 if subscribers != nil { 78 for name, subscriber := range subscribers[opt.AppName] { 79 log.Printf("%v [Gofusion] %s %s %s subscriber exiting...", 80 pid, app, config.ComponentMessageQueue, name) 81 if err := subscriber.close(); err == nil { 82 log.Printf("%v [Gofusion] %s %s %s subscriber exited", 83 pid, app, config.ComponentMessageQueue, name) 84 } else { 85 log.Printf("%v [Gofusion] %s %s %s subscriber exit failed: %s", 86 pid, app, config.ComponentMessageQueue, name, err) 87 } 88 } 89 delete(subscribers, opt.AppName) 90 } 91 } 92 } 93 94 func addInstance(ctx context.Context, name string, conf *Conf, opt *config.InitOption) { 95 var logger watermill.LoggerAdapter 96 if utils.IsStrNotBlank(conf.Logger) { 97 loggerType := inspect.TypeOf(conf.Logger) 98 loggerValue := reflect.New(loggerType) 99 if loggerValue.Type().Implements(customLoggerType) { 100 l := fusLog.Use(conf.LogInstance, fusLog.AppName(opt.AppName)) 101 loggerValue.Interface().(customLogger).Init(l, opt.AppName, name) 102 } 103 logger = loggerValue.Convert(watermillLoggerType).Interface().(watermill.LoggerAdapter) 104 } 105 106 if conf.ConsumerConcurrency < 1 { 107 conf.ConsumerConcurrency = 1 108 } 109 110 var ( 111 puber Publisher 112 suber Subscriber 113 ) 114 newFunc, ok := newFn[conf.Type] 115 if ok { 116 puber, suber = newFunc(ctx, opt.AppName, name, conf, logger) 117 } else { 118 panic(errors.Errorf("unknown message queue type: %+v", conf.Type)) 119 } 120 121 locker.Lock() 122 defer locker.Unlock() 123 if suber != nil { 124 if subscribers == nil { 125 subscribers = make(map[string]map[string]Subscriber) 126 } 127 if subscribers[opt.AppName] == nil { 128 subscribers[opt.AppName] = make(map[string]Subscriber) 129 } 130 if _, ok := subscribers[name]; ok { 131 panic(ErrDuplicatedSubscriberName) 132 } 133 subscribers[opt.AppName][name] = suber 134 135 if routers == nil { 136 routers = make(map[string]map[string]IRouter) 137 } 138 if routers[opt.AppName] == nil { 139 routers[opt.AppName] = make(map[string]IRouter) 140 } 141 if _, ok := routers[opt.AppName][name]; ok { 142 panic(ErrDuplicatedRouterName) 143 } 144 routers[opt.AppName][name] = newRouter(ctx, opt.AppName, name, conf, puber, suber, logger) 145 146 // ioc 147 if opt.DI != nil { 148 opt.DI. 149 MustProvide(func() Subscriber { return sub(name, AppName(opt.AppName)) }, di.Name(name)). 150 MustProvide(func() IRouter { return Use(name, AppName(opt.AppName)) }, di.Name(name)) 151 } 152 153 } 154 155 if puber != nil { 156 if publishers == nil { 157 publishers = make(map[string]map[string]Publisher) 158 } 159 if publishers[opt.AppName] == nil { 160 publishers[opt.AppName] = make(map[string]Publisher) 161 } 162 if _, ok := publishers[opt.AppName][name]; ok { 163 panic(ErrDuplicatedPublisherName) 164 } 165 publishers[opt.AppName][name] = puber 166 167 // ioc 168 if opt.DI != nil { 169 opt.DI.MustProvide(func() Publisher { return Pub(name, AppName(opt.AppName)) }, di.Name(name)) 170 } 171 } 172 } 173 174 type useOption struct { 175 appName string 176 } 177 178 func AppName(name string) utils.OptionFunc[useOption] { 179 return func(o *useOption) { 180 o.appName = name 181 } 182 } 183 184 func sub(name string, opts ...utils.OptionExtender) Subscriber { 185 opt := utils.ApplyOptions[useOption](opts...) 186 187 locker.RLock() 188 defer locker.RUnlock() 189 subscribers, ok := subscribers[opt.appName] 190 if !ok { 191 panic(errors.Errorf("mq subscriber instance not found for app: %s", opt.appName)) 192 } 193 subscriber, ok := subscribers[name] 194 if !ok { 195 panic(errors.Errorf("mq subscriber instance not found for name: %s", name)) 196 } 197 return subscriber 198 } 199 200 func Pub(name string, opts ...utils.OptionExtender) Publisher { 201 opt := utils.ApplyOptions[useOption](opts...) 202 203 locker.RLock() 204 defer locker.RUnlock() 205 publishers, ok := publishers[opt.appName] 206 if !ok { 207 panic(errors.Errorf("mq publisher instance not found for app: %s", opt.appName)) 208 } 209 publisher, ok := publishers[name] 210 if !ok { 211 panic(errors.Errorf("mq publisher instance not found for name: %s", name)) 212 } 213 return publisher 214 } 215 216 func Sub(name string, opts ...utils.OptionExtender) Subscriber { 217 opt := utils.ApplyOptions[useOption](opts...) 218 219 locker.RLock() 220 defer locker.RUnlock() 221 subscribers, ok := subscribers[opt.appName] 222 if !ok { 223 panic(errors.Errorf("mq subscriber instance not found for app: %s", opt.appName)) 224 } 225 subscriber, ok := subscribers[name] 226 if !ok { 227 panic(errors.Errorf("mq subscriber instance not found for name: %s", name)) 228 } 229 return subscriber 230 } 231 232 func Use(name string, opts ...utils.OptionExtender) IRouter { 233 opt := utils.ApplyOptions[useOption](opts...) 234 235 locker.RLock() 236 defer locker.RUnlock() 237 routers, ok := routers[opt.appName] 238 if !ok { 239 panic(errors.Errorf("mq router instance not found for app: %s", opt.appName)) 240 } 241 r, ok := routers[name] 242 if !ok { 243 panic(errors.Errorf("mq router instance not found for name: %s", name)) 244 } 245 return r 246 } 247 248 func init() { 249 config.AddComponent(config.ComponentMessageQueue, Construct, config.WithFlag(&flagString)) 250 }