Skip to content

Commit

Permalink
package: shutdown -> graceful
Browse files Browse the repository at this point in the history
  • Loading branch information
andeya committed Jul 11, 2017
1 parent b968142 commit 0e2aeba
Show file tree
Hide file tree
Showing 6 changed files with 409 additions and 159 deletions.
100 changes: 58 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ Common and useful utils for the Go project development.

- [Calendar](#calendar) Chinese Lunar Calendar, Solar Calendar and cron time rules
- [CoarseTime](#coarsetime) Current time truncated to the nearest second
- [Graceful](#graceful) Shutdown or reboot current process gracefully.
- [GoPool](#gopool) Goroutines' pool
- [ResPool](#respool) Resources' pool
- [Shutdown](#shutdown) Close current program gracefully
- [Various](#various) Various small functions


Expand Down Expand Up @@ -49,6 +49,63 @@ This is a faster alternative to time.Now().
func CoarseTimeNow() time.Time
```

### Graceful

Shutdown or reboot current process gracefully.

- import it

```go
"github.com/henrylee2cn/goutil/graceful"
```

- SetShutdown sets the function which is called after the process shutdown,
and the time-out period for the process shutdown.
If 0<=timeout<5s, automatically use 'MinShutdownTimeout'(5s).
If timeout<0, indefinite period.
'preCloseFunc' is executed before closing process, but not guaranteed to be completed.
'postCloseFunc' is executed after process are closed, but not guaranteed to be completed.

```go
func SetShutdown(timeout time.Duration, fn ...func() error)
```

- Shutdown closes all the frame process gracefully.
Parameter timeout is used to reset time-out period for the process shutdown.

```go
func Shutdown(timeout ...time.Duration)
```

- Reboot all the frame process gracefully.
Notes: Windows system are not supported!

```
func Reboot(timeout ...time.Duration)
```

- SetExtractProcFiles sets extract proc files only for reboot.
Notes: Windows system are not supported!

```
func SetExtractProcFiles(extractProcFiles []*os.File)
```

- Logger logger interface

```go
Logger interface {
Infof(format string, v ...interface{})
Errorf(format string, v ...interface{})
}

- SetLog resets logger

```go
func SetLog(logger Logger)
```
```

### GoPool

GoPool is a Goroutines pool. It can control concurrent numbers, reuse goroutines.
Expand Down Expand Up @@ -247,47 +304,6 @@ If the same name exists, will close and cover it.
func (c *ResPools) Set(pool ResPool)
```

### Shutdown

Close current program gracefully.

- import it

```go
"github.com/henrylee2cn/goutil/shutdown"
```

- SetShutdown sets the function which is called after current program shutdown,
and the time-out period for current program shutdown.
If parameter timeout is 0, automatically use default `defaultTimeout`(60s).
If parameter timeout less than 0, it is indefinite period.
The finalizer function is executed before the shutdown deadline, but it is not guaranteed to be completed.

```go
func SetShutdown(timeout time.Duration, fn ...func() error)
```

- Shutdown closes current program gracefully.
Parameter timeout is used to reset time-out period for current program shutdown.

```go
func Shutdown(timeout ...time.Duration)
```
- Logger logger interface

```go
Logger interface {
Infof(format string, v ...interface{})
Errorf(format string, v ...interface{})
}

- SetLog resets logger

```go
func SetLog(logger Logger)
```
```

### Various

Various small functions.
Expand Down
104 changes: 104 additions & 0 deletions graceful/grace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// graceful package shutdown or reboot current process gracefully.
//
// Copyright 2016 HenryLee. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package graceful

import (
"context"
"time"
)

// MinShutdownTimeout the default time-out period for the process shutdown.
const MinShutdownTimeout = 5 * time.Second

var (
shutdownTimeout time.Duration
preCloseFunc func() error
postCloseFunc func() error
)

// SetShutdown sets the function which is called after the process shutdown,
// and the time-out period for the process shutdown.
// If 0<=timeout<5s, automatically use 'MinShutdownTimeout'(5s).
// If timeout<0, indefinite period.
// 'preCloseFunc' is executed before closing process, but not guaranteed to be completed.
// 'postCloseFunc' is executed after process are closed, but not guaranteed to be completed.
func SetShutdown(timeout time.Duration, preCloseFunc, postCloseFunc func() error) {
if timeout < 0 {
shutdownTimeout = 1<<63 - 1
} else if timeout < MinShutdownTimeout {
shutdownTimeout = MinShutdownTimeout
} else {
shutdownTimeout = timeout
}
preCloseFunc = preCloseFunc
postCloseFunc = postCloseFunc
}

// Shutdown closes all the frame process gracefully.
// Parameter timeout is used to reset time-out period for the process shutdown.
func Shutdown(timeout ...time.Duration) {
log.Infof("shutting down process...")

contextExec(timeout, "shutdown", func(ctxTimeout context.Context) <-chan struct{} {
endCh := make(chan struct{})
go func() {
defer close(endCh)

var graceful = true

if preCloseFunc != nil {
if err := preCloseFunc(); err != nil {
log.Errorf("[shutdown-preClose] %s", err.Error())
graceful = false
}
}

graceful = shutdown(ctxTimeout, "shutdown") && graceful

if graceful {
log.Infof("process are shutted down gracefully!")
} else {
log.Infof("process are shutted down, but not gracefully!")
}
}()
return endCh
})
}

func contextExec(timeout []time.Duration, action string, deferCallback func(ctxTimeout context.Context) <-chan struct{}) {
if len(timeout) > 0 {
SetShutdown(timeout[0], preCloseFunc, postCloseFunc)
}
ctxTimeout, _ := context.WithTimeout(context.Background(), shutdownTimeout)
select {
case <-ctxTimeout.Done():
if err := ctxTimeout.Err(); err != nil {
log.Errorf("[%s-timeout] %s", action, err.Error())
}
case <-deferCallback(ctxTimeout):
}
}

func shutdown(ctxTimeout context.Context, action string) bool {
if postCloseFunc != nil {
if err := postCloseFunc(); err != nil {
log.Errorf("[%s-postClose] %s", action, err.Error())
return false
}
}

return true
}
45 changes: 45 additions & 0 deletions graceful/grace_a.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// +build windows
//
// Copyright 2016 HenryLee. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package graceful

import (
"os"
"os/signal"
"time"
)

func graceSignal() {
// subscribe to SIGINT signals
ch := make(chan os.Signal)
signal.Notify(ch, os.Interrupt, os.Kill)
defer func() {
os.Exit(0)
}()
<-ch // wait for SIGINT
signal.Stop(ch)
Shutdown()
}

// Reboot all the frame process gracefully.
// Notes: Windows system are not supported!
func Reboot(timeout ...time.Duration) {
log.Infof("windows system doesn't support reboot! call Shutdown() is recommended.")
}

// SetExtractProcFiles sets extract proc files only for reboot.
// Notes: Windows system are not supported!
func SetExtractProcFiles([]*os.File) {}
Loading

0 comments on commit 0e2aeba

Please sign in to comment.