Skip to content

Commit

Permalink
add module: app、zaplog、common
Browse files Browse the repository at this point in the history
  • Loading branch information
lazychanger committed Sep 13, 2023
1 parent 52c24fd commit c256c93
Show file tree
Hide file tree
Showing 11 changed files with 647 additions and 0 deletions.
48 changes: 48 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package app

import "context"

type Application interface {
Init(ctx context.Context) error
Run(ctx context.Context) error
Reload(ctx context.Context) error
Stop(ctx context.Context) error
}

type NamedApplication interface {
Application
Name() string
}

type TestApplication struct {
IsEnable bool

stop chan struct{}
}

func (t *TestApplication) Init(ctx context.Context) error {
return nil
}

func (t *TestApplication) Run(ctx context.Context) error {
<-t.stop

return nil
}

func (t *TestApplication) Reload(ctx context.Context) error {
if err := t.Stop(ctx); err != nil {
return err
}

if err := t.Run(ctx); err != nil {
return err
}

return nil
}

func (t *TestApplication) Stop(ctx context.Context) error {
t.stop <- struct{}{}
return nil
}
64 changes: 64 additions & 0 deletions app/grace/grace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//go:build !windows

package grace

import (
"context"
"github.com/lazychanger/go-contrib/app"
"github.com/lazychanger/go-contrib/zaplog"
"os"
"os/signal"
"runtime/debug"
"syscall"
"time"
)

func GracefulRun(ctx context.Context, application app.Application) error {
defer func() {
if err := recover(); err != nil {
zaplog.Warnln(err)
debug.PrintStack()
}
}()

if err := application.Init(ctx); err != nil {
return err
}

sigs := make(chan os.Signal)
done := make(chan error)
defer func() { close(sigs); close(done) }()

signal.Notify(sigs, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT)

go func() {
done <- application.Run(ctx)
}()

for {
select {
case sig := <-sigs:
zaplog.Infof("got signal: %s", sig.String())

switch sig {
case syscall.SIGHUP:
// reload failed
if err := application.Reload(ctx); err != nil {
return err
}
default:
subCtx, cancel := context.WithDeadline(ctx, time.Now().Add(time.Second*10))

if err := application.Stop(subCtx); err != nil {
zaplog.Warnf("application run stop failed: %s", err)
}

cancel()
return <-done
}

case err := <-done:
return err
}
}
}
25 changes: 25 additions & 0 deletions app/grace/grace_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//go:build windows

package grace

import (
"context"
"github.com/lazychanger/go-contrib/app"
"time"
)

func GracefulRun(ctx context.Context, application app.Application) error {
stop := make(chan error)
done := make(chan error)
go func() {
done <- application.Run(ctx)
}()

<-stop

ctx, cancel := context.WithDeadline(ctx, time.Now().Add(time.Second*10))
defer cancel()
application.Stop(ctx)

return <-done
}
9 changes: 9 additions & 0 deletions app/multi/enabled.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package multi

import "github.com/lazychanger/go-contrib/app"

type EnabledApplication interface {
app.Application

Enabled() bool
}
109 changes: 109 additions & 0 deletions app/multi/multi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package multi

import (
"context"
"github.com/lazychanger/go-contrib/app"
"github.com/lazychanger/go-contrib/zaplog"
"golang.org/x/sync/errgroup"
"reflect"
)

type multi struct {
apps []app.Application
}

func (m *multi) Init(basectx context.Context) error {
group := &errgroup.Group{}

for _, _app := range m.apps {
cur := _app
group.Go(func() error {
subctx, cancel := context.WithCancel(basectx)
defer cancel()

return cur.Init(subctx)
})
}
return group.Wait()
}

func (m *multi) Run(basectx context.Context) error {
group := &errgroup.Group{}

for _, _app := range m.apps {
cur := _app

group.Go(func() error {
if _, ok := cur.(*multi); !ok {
name := reflect.TypeOf(cur).String()
if namedApp, ok := cur.(app.NamedApplication); ok {
name = namedApp.Name()
}

zaplog.Debugf("%s is running", name)

defer func() {
zaplog.Debugf("%s has been done", name)
}()
}

subctx, cancel := context.WithCancel(basectx)
defer cancel()

return cur.Run(subctx)
})
}

return group.Wait()
}

func (m *multi) Reload(basectx context.Context) error {
group := &errgroup.Group{}

for _, _app := range m.apps {
cur := _app

group.Go(func() error {
subctx, cancel := context.WithCancel(basectx)
defer cancel()

return cur.Reload(subctx)
})
}
return group.Wait()
}

func (m *multi) Stop(basectx context.Context) error {
group := &errgroup.Group{}

for _, _app := range m.apps {
cur := _app
group.Go(func() error {
subctx, cancel := context.WithCancel(basectx)
defer cancel()

return cur.Stop(subctx)
})
}
return group.Wait()
}

func (m *multi) Enabled() bool {
return true
}

func New(apps ...app.Application) app.Application {

sortApps := &sortApplications{apps: make([]app.Application, 0)}

for _, application := range apps {
if enabledApp, ok := application.(EnabledApplication); !ok || !enabledApp.Enabled() {
continue
}
sortApps.apps = append(sortApps.apps, application)
}

return &multi{
apps: sortApps.Applications(),
}
}
56 changes: 56 additions & 0 deletions app/multi/sort.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package multi

import (
"github.com/lazychanger/go-contrib/app"
"sort"
)

type SortApplication interface {
app.Application

Sort() int
}

type sortApplications struct {
apps []app.Application
sorted bool
}

func (s *sortApplications) Len() int {
return len(s.apps)
}

func (s *sortApplications) Less(i, j int) bool {
return getSort(s.apps[i]) > getSort(s.apps[j])
}

func (s *sortApplications) Swap(i, j int) {
s.apps[i], s.apps[j] = s.apps[j], s.apps[i]
}

func (s *sortApplications) Applications() []app.Application {
if !s.sorted {
sort.Sort(s)
s.sorted = true
}

return s.apps
}

func getSort(app app.Application) int {
if sortApp, ok := app.(SortApplication); ok {
return sortApp.Sort()
} else {
return 0
}
}

type TestSortApplication struct {
app.TestApplication

SortVal int
}

func (t *TestSortApplication) Sort() int {
return t.SortVal
}
Loading

0 comments on commit c256c93

Please sign in to comment.