-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
52c24fd
commit c256c93
Showing
11 changed files
with
647 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
Oops, something went wrong.