| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- package fairwind
- import (
- "context"
- "os"
- "os/signal"
- "sync"
- "syscall"
- )
- type ApplicationModule interface {
- Name() string
- Start() error
- Stop() error
- }
- type ApplicationModuleBuilder func(ctx context.Context, log *Log) (ApplicationModule, error)
- type Application struct {
- ctx context.Context
- cancel func()
- log *Log
- modules []ApplicationModule
- }
- func Run(builders ...ApplicationModuleBuilder) {
- ctx, cancel := context.WithCancel(context.Background())
- log := NewLog(NewLogFormatterJSON())
- modules := []ApplicationModule{}
- for _, builder := range builders {
- module, err := builder(ctx, log)
- if err != nil {
- log.Error("can't build module", LogValue("name", module.Name()), LogError(err))
- cancel()
- return
- }
- modules = append(modules, module)
- }
- this := &Application{
- ctx: ctx,
- cancel: cancel,
- log: log,
- modules: modules,
- }
- this.log.Information("starting application")
- this.startup()
- channel := make(chan os.Signal, 1)
- signal.Notify(channel, syscall.SIGTERM, syscall.SIGINT)
- <-channel
- this.log.Information("stopping application")
- this.cancel()
- this.shutdown()
- }
- func (this *Application) startup() {
- waitGroup := sync.WaitGroup{}
- waitGroup.Add(len(this.modules))
- start := func(log *Log, module ApplicationModule) {
- log.Information("starting module", LogValue("module", module.Name()))
- err := module.Start()
- if err != nil {
- log.Error("error starting module", LogValue("module", module.Name()), LogError(err))
- } else {
- log.Information("module started", LogValue("module", module.Name()))
- }
- waitGroup.Done()
- }
- for _, module := range this.modules {
- go start(this.log, module)
- }
- waitGroup.Wait()
- }
- func (this *Application) shutdown() {
- waitGroup := sync.WaitGroup{}
- waitGroup.Add(len(this.modules))
- stop := func(log *Log, module ApplicationModule) {
- log.Information("stopping module", LogValue("module", module.Name()))
- err := module.Stop()
- if err != nil {
- log.Error("error stopping module", LogValue("module", module.Name()), LogError(err))
- } else {
- log.Information("module stopped", LogValue("module", module.Name()))
- }
- waitGroup.Done()
- }
- for _, module := range this.modules {
- go stop(this.log, module)
- }
- waitGroup.Wait()
- }
|