Update to 6.0.9: Add PostInterrupt plugin. Read HISTORY.md

- Add `PostInterrupt` plugin, useful for customization of the
**os.Interrupt** singal, before that Iris closed the server
automatically.

```go
iris.Plugins.PostInterrupt(func(s *Framework){
// when os.Interrupt signal is fired the body of this function will be
fired,
// you're responsible for closing the server with s.Close()

// if that event is not registered then the framework
// will close the server for you.

/* Do  any custom cleanup and finally call the s.Close()
remember you have the iris.Plugins.PreClose(func(s *Framework)) event
too
so you can split your logic in two logically places.
*/

})

```
This commit is contained in:
Gerasimos (Makis) Maropoulos 2017-01-11 16:23:38 +02:00
parent c5f95ba78a
commit 5ad7c6e01f
5 changed files with 117 additions and 18 deletions

View File

@ -1,4 +1,4 @@
- Version : **6.0.8**
- Version : **6.0.9**
- Operating System:

View File

@ -2,6 +2,29 @@
**How to upgrade**: remove your `$GOPATH/src/github.com/kataras` folder, open your command-line and execute this command: `go get -u github.com/kataras/iris/iris`.
## 6.0.8 -> 6.0.9
- Add `PostInterrupt` plugin, useful for customization of the **os.Interrupt** singal, before that Iris closed the server automatically.
```go
iris.Plugins.PostInterrupt(func(s *Framework){
// when os.Interrupt signal is fired the body of this function will be fired,
// you're responsible for closing the server with s.Close()
// if that event is not registered then the framework
// will close the server for you.
/* Do any custom cleanup and finally call the s.Close()
remember you have the iris.Plugins.PreClose(func(s *Framework)) event too
so you can split your logic in two logically places.
*/
})
```
## 6.0.7 -> 6.0.8
- Add `iris.UseTemplateFunc(functionName string, function interface{})`. You could always set custom template funcs by using each of [template engine's](https://github.com/kataras/go-template) configuration but this function will help newcomers to start creating their custom template funcs.

View File

@ -18,7 +18,7 @@
<br/>
<a href="https://github.com/kataras/iris/blob/master/HISTORY.md"><img src="https://img.shields.io/badge/%20version%20-%206.0.8%20-blue.svg?style=flat-square" alt="CHANGELOG/HISTORY"></a>
<a href="https://github.com/kataras/iris/blob/master/HISTORY.md"><img src="https://img.shields.io/badge/%20version%20-%206.0.9%20-blue.svg?style=flat-square" alt="CHANGELOG/HISTORY"></a>
<a href="https://github.com/iris-contrib/examples"><img src="https://img.shields.io/badge/%20examples-repository-3362c2.svg?style=flat-square" alt="Examples"></a>
@ -129,7 +129,7 @@ $ go run hellojson.go
```
> TIP #1> $ iris run main.go to enable hot-reload on .go source code changes.
> TIP #2> iris.Config.IsDevelopment = true to monitor the changes you make in the templates.
> TIP #2> iris.Config.IsDevelopment = true to monitor the changes you make in the templates.
Open your browser or any other http client at http://localhost:6000/api/user/42.
@ -947,7 +947,7 @@ I recommend testing your API using this new library, [httpexpect](https://github
Versioning
------------
Current: **v6.0.8**
Current: **v6.0.9**
Older: **[v5/fasthttp](https://github.com/kataras/iris/tree/5.0.0)**

64
iris.go
View File

@ -66,6 +66,7 @@ import (
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/kataras/go-errors"
@ -80,7 +81,7 @@ const (
// IsLongTermSupport flag is true when the below version number is a long-term-support version
IsLongTermSupport = false
// Version is the current version number of the Iris web framework
Version = "6.0.8"
Version = "6.0.9"
banner = ` _____ _
|_ _| (_)
@ -478,21 +479,51 @@ func (s *Framework) Serve(ln net.Listener) error {
}
// maybe a 'race' here but user should not call .Serve more than one time especially in more than one go routines...
s.ln = ln
// build the handler and all other components
s.Build()
// fire all PreListen plugins
s.Plugins.DoPreListen(s)
// This didn't helped me ,here, but maybe can help you:
// https://www.oreilly.com/learning/run-strikingly-fast-parallel-file-searches-in-go-with-sync-errgroup?utm_source=golangweekly&utm_medium=email
// new experimental package: errgroup
// catch any panics to the user defined logger.
defer func() {
if err := recover(); err != nil {
s.Logger.Panic(err)
}
}()
// start the server in goroutine, .Available will block instead
go func() { s.Must(s.srv.Serve(ln)) }()
// prepare for 'after serve' actions
var stop uint32
go func() {
// wait for the server's Serve func (309 mill is a lot or not, I found that this number is the perfect for most of the environments.)
time.Sleep(309 * time.Millisecond)
if atomic.LoadUint32(&stop) > 0 {
return
}
// print the banner
// fire the PostListen plugins
// wait for system channel interrupt
// fire the PostInterrupt plugins or close and exit.
s.postServe()
}()
serverStartUpErr := s.srv.Serve(ln)
if serverStartUpErr != nil {
// if an error then it would be nice to stop the banner and all next plugin events.
atomic.AddUint32(&stop, 1)
}
// finally return the error or block here, remember,
// you can always use the iris.Available to 'see' if and when the server is up (virtually),
// until go1.8 these are our best options.
return serverStartUpErr
}
// runs only when server starts without errors
// what it does?
// 0. print the banner
// 1. fire the PostListen plugins
// 2. wait for system channel interrupt
// 3. fire the PostInterrupt plugins or close and exit.
func (s *Framework) postServe() {
if !s.Config.DisableBanner {
bannerMessage := fmt.Sprintf("%s: Running at %s", time.Now().Format(s.Config.TimeFormat), s.Config.VHost)
@ -506,17 +537,22 @@ func (s *Framework) Serve(ln net.Listener) error {
s.Plugins.DoPostListen(s)
go func() { s.Available <- true }()
ch := make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt)
<-ch
if err := s.Close(); err != nil {
if s.Config.IsDevelopment {
s.Logger.Printf("Error while closing the server: %s\n", err)
// catch custom plugin event for interrupt
s.Plugins.DoPostInterrupt(s)
if !s.Plugins.PostInterruptFired() {
// if no PostInterrupt events fired, then I assume that the user doesn't cares
// so close the server automatically.
if err := s.Close(); err != nil {
if s.Config.IsDevelopment {
s.Logger.Printf("Error while closing the server: %s\n", err)
}
}
return err
os.Exit(1)
}
os.Exit(1)
return nil
}
// Listen starts the standalone http server

View File

@ -89,6 +89,20 @@ type (
}
// PostListenFunc implements the simple function listener for the PostListen(*Framework)
PostListenFunc func(*Framework)
// pluginPostInterrupt implements the PostInterrupt(*Framework) method
pluginPostInterrupt interface {
// PostInterrupt it's being called only one time, when os.Interrupt system event catched
// graceful shutdown can be done here
//
// Read more here: https://github.com/kataras/iris/blob/master/HISTORY.md#608---609
PostInterrupt(*Framework)
}
// PostInterruptFunc implements the simple function listener for the PostInterrupt(*Framework)
//
// Read more here: https://github.com/kataras/iris/blob/master/HISTORY.md#608---609
PostInterruptFunc func(*Framework)
// pluginPreClose implements the PreClose(*Framework) method
pluginPreClose interface {
// PreClose it's being called only one time, BEFORE the Iris .Close method
@ -139,6 +153,9 @@ type (
PostListen(PostListenFunc)
DoPostListen(*Framework)
PostListenFired() bool
PostInterrupt(PostInterruptFunc)
DoPostInterrupt(*Framework)
PostInterruptFired() bool
PreClose(PreCloseFunc)
DoPreClose(*Framework)
PreCloseFired() bool
@ -520,6 +537,29 @@ func (p *pluginContainer) PostListenFired() bool {
return p.Fired("postlisten") > 0
}
// PostInterrupt adds a PostInterrupt plugin-function to the plugin flow container
//
// Read more here: https://github.com/kataras/iris/blob/master/HISTORY.md#608---609
func (p *pluginContainer) PostInterrupt(fn PostInterruptFunc) {
p.Add(fn)
}
// DoPostInterrupt raise all plugins which has the PostInterrupt method
func (p *pluginContainer) DoPostInterrupt(station *Framework) {
for i := range p.activatedPlugins {
// check if this method exists on our plugin obj, these are optionaly and call it
if pluginObj, ok := p.activatedPlugins[i].(pluginPostInterrupt); ok {
pluginObj.PostInterrupt(station)
p.fire("postinterrupt")
}
}
}
// PostInterruptFired returns true if PostInterrupt event/ plugin type is fired at least one time
func (p *pluginContainer) PostInterruptFired() bool {
return p.Fired("postinterrupt") > 0
}
// PreClose adds a PreClose plugin-function to the plugin flow container
func (p *pluginContainer) PreClose(fn PreCloseFunc) {
p.Add(fn)