application.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. package mhaya
  2. import (
  3. "os"
  4. "os/signal"
  5. "sync/atomic"
  6. "syscall"
  7. cconst "github.com/mhaya/const"
  8. ctime "github.com/mhaya/extend/time"
  9. cutils "github.com/mhaya/extend/utils"
  10. cfacade "github.com/mhaya/facade"
  11. clog "github.com/mhaya/logger"
  12. cactor "github.com/mhaya/net/actor"
  13. cserializer "github.com/mhaya/net/serializer"
  14. cprofile "github.com/mhaya/profile"
  15. )
  16. const (
  17. Cluster NodeMode = 1 // 集群模式
  18. Standalone NodeMode = 2 // 单机模式
  19. )
  20. type (
  21. NodeMode byte
  22. Application struct {
  23. cfacade.INode
  24. isFrontend bool
  25. nodeMode NodeMode
  26. startTime ctime.MhayaTime // application start time
  27. running int32 // is running
  28. dieChan chan bool // wait for end application
  29. onShutdownFn []func() // on shutdown execute functions
  30. components []cfacade.IComponent // all components
  31. serializer cfacade.ISerializer // serializer
  32. discovery cfacade.IDiscovery // discovery component
  33. cluster cfacade.ICluster // cluster component
  34. actorSystem *cactor.Component // actor system
  35. netParser cfacade.INetParser // net packet parser
  36. }
  37. )
  38. // NewApp create new application instance
  39. func NewApp(profileFilePath, nodeId string, isFrontend bool, mode NodeMode) *Application {
  40. node, err := cprofile.Init(profileFilePath, nodeId)
  41. if err != nil {
  42. panic(err)
  43. }
  44. return NewAppNode(node, isFrontend, mode)
  45. }
  46. func NewAppNode(node cfacade.INode, isFrontend bool, mode NodeMode) *Application {
  47. // set logger
  48. clog.SetNodeLogger(node)
  49. // print version info
  50. clog.Info(cconst.GetLOGO())
  51. app := &Application{
  52. INode: node,
  53. serializer: cserializer.NewJSON(),
  54. isFrontend: isFrontend,
  55. nodeMode: mode,
  56. startTime: ctime.Now(),
  57. running: 0,
  58. dieChan: make(chan bool),
  59. actorSystem: cactor.New(),
  60. }
  61. return app
  62. }
  63. func (a *Application) IsFrontend() bool {
  64. return a.isFrontend
  65. }
  66. func (a *Application) NodeMode() NodeMode {
  67. return a.nodeMode
  68. }
  69. func (a *Application) Running() bool {
  70. return a.running > 0
  71. }
  72. func (a *Application) DieChan() chan bool {
  73. return a.dieChan
  74. }
  75. func (a *Application) Register(components ...cfacade.IComponent) {
  76. if a.Running() {
  77. return
  78. }
  79. for _, c := range components {
  80. if c == nil || c.Name() == "" {
  81. clog.Errorf("[component = %T] name is nil", c)
  82. return
  83. }
  84. result := a.Find(c.Name())
  85. if result != nil {
  86. clog.Errorf("[component name = %s] is duplicate.", c.Name())
  87. return
  88. }
  89. a.components = append(a.components, c)
  90. }
  91. }
  92. func (a *Application) Find(name string) cfacade.IComponent {
  93. if name == "" {
  94. return nil
  95. }
  96. for _, component := range a.components {
  97. if component.Name() == name {
  98. return component
  99. }
  100. }
  101. return nil
  102. }
  103. // Remove component by name
  104. func (a *Application) Remove(name string) cfacade.IComponent {
  105. if name == "" {
  106. return nil
  107. }
  108. var removeComponent cfacade.IComponent
  109. for i := 0; i < len(a.components); i++ {
  110. if a.components[i].Name() == name {
  111. removeComponent = a.components[i]
  112. a.components = append(a.components[:i], a.components[i+1:]...)
  113. i--
  114. }
  115. }
  116. return removeComponent
  117. }
  118. func (a *Application) All() []cfacade.IComponent {
  119. return a.components
  120. }
  121. func (a *Application) OnShutdown(fn ...func()) {
  122. a.onShutdownFn = append(a.onShutdownFn, fn...)
  123. }
  124. // Startup load components before startup
  125. func (a *Application) Startup() {
  126. defer func() {
  127. if r := recover(); r != nil {
  128. clog.Error(r)
  129. }
  130. }()
  131. if a.Running() {
  132. clog.Error("Application has running.")
  133. return
  134. }
  135. defer func() {
  136. clog.Flush()
  137. }()
  138. // register actor system
  139. a.Register(a.actorSystem)
  140. // add connector component
  141. if a.netParser != nil {
  142. for _, connector := range a.netParser.Connectors() {
  143. a.Register(connector)
  144. }
  145. }
  146. clog.Info("-------------------------------------------------")
  147. clog.Infof("[nodeId = %s] application is starting...", a.NodeId())
  148. clog.Infof("[nodeType = %s]", a.NodeType())
  149. clog.Infof("[pid = %d]", os.Getpid())
  150. clog.Infof("[startTime = %s]", a.StartTime())
  151. clog.Infof("[profilePath = %s]", cprofile.Path())
  152. clog.Infof("[profileName = %s]", cprofile.Name())
  153. clog.Infof("[env = %s]", cprofile.Env())
  154. clog.Infof("[debug = %v]", cprofile.Debug())
  155. clog.Infof("[printLevel = %s]", cprofile.PrintLevel())
  156. clog.Infof("[logLevel = %s]", clog.DefaultLogger.LogLevel)
  157. clog.Infof("[stackLevel = %s]", clog.DefaultLogger.StackLevel)
  158. clog.Infof("[writeFile = %v]", clog.DefaultLogger.EnableWriteFile)
  159. clog.Infof("[serializer = %s]", a.serializer.Name())
  160. clog.Info("-------------------------------------------------")
  161. // component list
  162. for _, c := range a.components {
  163. c.Set(a)
  164. clog.Infof("[component = %s] is added.", c.Name())
  165. }
  166. clog.Info("-------------------------------------------------")
  167. // execute Init()
  168. for _, c := range a.components {
  169. clog.Infof("[component = %s] -> OnInit().", c.Name())
  170. c.Init()
  171. }
  172. clog.Info("-------------------------------------------------")
  173. // execute OnAfterInit()
  174. for _, c := range a.components {
  175. clog.Infof("[component = %s] -> OnAfterInit().", c.Name())
  176. c.OnAfterInit()
  177. }
  178. // load net packet parser
  179. if a.isFrontend {
  180. if a.netParser == nil {
  181. clog.Panic("net packet parser is nil.")
  182. }
  183. a.netParser.Load(a)
  184. }
  185. clog.Info("-------------------------------------------------")
  186. spendTime := a.startTime.DiffInMillisecond(ctime.Now())
  187. clog.Infof("[spend time = %dms] application is running.", spendTime)
  188. clog.Info("-------------------------------------------------")
  189. // set application is running
  190. atomic.AddInt32(&a.running, 1)
  191. sg := make(chan os.Signal, 1)
  192. signal.Notify(sg, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
  193. select {
  194. case <-a.dieChan:
  195. clog.Info("invoke shutdown().")
  196. case s := <-sg:
  197. clog.Infof("receive shutdown signal = %v.", s)
  198. }
  199. // stop status
  200. atomic.StoreInt32(&a.running, 0)
  201. clog.Info("------- application will shutdown -------")
  202. if a.onShutdownFn != nil {
  203. for _, f := range a.onShutdownFn {
  204. cutils.Try(func() {
  205. f()
  206. }, func(errString string) {
  207. clog.Warnf("[onShutdownFn] error = %s", errString)
  208. })
  209. }
  210. }
  211. //all components in reverse order
  212. for i := len(a.components) - 1; i >= 0; i-- {
  213. cutils.Try(func() {
  214. clog.Infof("[component = %s] -> OnBeforeStop().", a.components[i].Name())
  215. a.components[i].OnBeforeStop()
  216. }, func(errString string) {
  217. clog.Warnf("[component = %s] -> OnBeforeStop(). error = %s", a.components[i].Name(), errString)
  218. })
  219. }
  220. for i := len(a.components) - 1; i >= 0; i-- {
  221. cutils.Try(func() {
  222. clog.Infof("[component = %s] -> OnStop().", a.components[i].Name())
  223. a.components[i].OnStop()
  224. }, func(errString string) {
  225. clog.Warnf("[component = %s] -> OnStop(). error = %s", a.components[i].Name(), errString)
  226. })
  227. }
  228. clog.Info("------- application has been shutdown... -------")
  229. }
  230. func (a *Application) Shutdown() {
  231. a.dieChan <- true
  232. }
  233. func (a *Application) Serializer() cfacade.ISerializer {
  234. return a.serializer
  235. }
  236. func (a *Application) Discovery() cfacade.IDiscovery {
  237. return a.discovery
  238. }
  239. func (a *Application) Cluster() cfacade.ICluster {
  240. return a.cluster
  241. }
  242. func (a *Application) ActorSystem() cfacade.IActorSystem {
  243. return a.actorSystem
  244. }
  245. func (a *Application) StartTime() string {
  246. return a.startTime.ToDateTimeFormat()
  247. }
  248. func (a *Application) SetSerializer(serializer cfacade.ISerializer) {
  249. if a.Running() || serializer == nil {
  250. return
  251. }
  252. a.serializer = serializer
  253. }
  254. func (a *Application) SetDiscovery(discovery cfacade.IDiscovery) {
  255. if a.Running() || discovery == nil {
  256. return
  257. }
  258. a.discovery = discovery
  259. }
  260. func (a *Application) SetCluster(cluster cfacade.ICluster) {
  261. if a.Running() || cluster == nil {
  262. return
  263. }
  264. a.cluster = cluster
  265. }
  266. func (a *Application) SetNetParser(netParser cfacade.INetParser) {
  267. if a.Running() || netParser == nil {
  268. return
  269. }
  270. a.netParser = netParser
  271. }