From 5ad7c6e01f5201bae7b989d7f068eb253894d1fd Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Wed, 11 Jan 2017 16:23:38 +0200 Subject: [PATCH] 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. */ }) ``` --- .github/ISSUE_TEMPLATE.md | 2 +- HISTORY.md | 23 ++++++++++++++ README.md | 6 ++-- iris.go | 64 ++++++++++++++++++++++++++++++--------- plugin.go | 40 ++++++++++++++++++++++++ 5 files changed, 117 insertions(+), 18 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 680ae776..6f8fbba2 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,4 +1,4 @@ -- Version : **6.0.8** +- Version : **6.0.9** - Operating System: diff --git a/HISTORY.md b/HISTORY.md index ab18f2b4..431f0edc 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -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. diff --git a/README.md b/README.md index 73b6e6ae..349e8567 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@
-CHANGELOG/HISTORY +CHANGELOG/HISTORY Examples @@ -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)** diff --git a/iris.go b/iris.go index a5c0857c..b578f7b0 100644 --- a/iris.go +++ b/iris.go @@ -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 diff --git a/plugin.go b/plugin.go index 9c9c3a8a..dfb8640e 100644 --- a/plugin.go +++ b/plugin.go @@ -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)