application.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. package fairwind
  2. import (
  3. "context"
  4. "os"
  5. "os/signal"
  6. "sync"
  7. "syscall"
  8. )
  9. type ApplicationModule interface {
  10. Name() string
  11. Start() error
  12. Stop() error
  13. }
  14. type ApplicationModuleBuilder func(ctx context.Context, log *Log) (ApplicationModule, error)
  15. type Application struct {
  16. ctx context.Context
  17. cancel func()
  18. log *Log
  19. modules []ApplicationModule
  20. }
  21. func Run(builders ...ApplicationModuleBuilder) {
  22. ctx, cancel := context.WithCancel(context.Background())
  23. log := NewLog(NewLogFormatterJSON())
  24. modules := []ApplicationModule{}
  25. for _, builder := range builders {
  26. module, err := builder(ctx, log)
  27. if err != nil {
  28. log.Error("can't build module", LogValue("name", module.Name()), LogError(err))
  29. cancel()
  30. return
  31. }
  32. modules = append(modules, module)
  33. }
  34. this := &Application{
  35. ctx: ctx,
  36. cancel: cancel,
  37. log: log,
  38. modules: modules,
  39. }
  40. this.log.Information("starting application")
  41. this.startup()
  42. channel := make(chan os.Signal, 1)
  43. signal.Notify(channel, syscall.SIGTERM, syscall.SIGINT)
  44. <-channel
  45. this.log.Information("stopping application")
  46. this.cancel()
  47. this.shutdown()
  48. }
  49. func (this *Application) startup() {
  50. waitGroup := sync.WaitGroup{}
  51. waitGroup.Add(len(this.modules))
  52. start := func(log *Log, module ApplicationModule) {
  53. log.Information("starting module", LogValue("module", module.Name()))
  54. err := module.Start()
  55. if err != nil {
  56. log.Error("error starting module", LogValue("module", module.Name()), LogError(err))
  57. } else {
  58. log.Information("module started", LogValue("module", module.Name()))
  59. }
  60. waitGroup.Done()
  61. }
  62. for _, module := range this.modules {
  63. go start(this.log, module)
  64. }
  65. waitGroup.Wait()
  66. }
  67. func (this *Application) shutdown() {
  68. waitGroup := sync.WaitGroup{}
  69. waitGroup.Add(len(this.modules))
  70. stop := func(log *Log, module ApplicationModule) {
  71. log.Information("stopping module", LogValue("module", module.Name()))
  72. err := module.Stop()
  73. if err != nil {
  74. log.Error("error stopping module", LogValue("module", module.Name()), LogError(err))
  75. } else {
  76. log.Information("module stopped", LogValue("module", module.Name()))
  77. }
  78. waitGroup.Done()
  79. }
  80. for _, module := range this.modules {
  81. go stop(this.log, module)
  82. }
  83. waitGroup.Wait()
  84. }