mirror of
https://github.com/kataras/iris.git
synced 2025-12-17 09:57:01 +00:00
don't fire ErrServerClosed on manually interrupt signals (CTRL/CMD+C)
Former-commit-id: 673c84dd13bb99c0926aa1b4a6b4eff9745403d8
This commit is contained in:
@@ -190,6 +190,8 @@ Other Improvements:
|
||||
|
||||

|
||||
|
||||
- Server will not return neither log the `ErrServerClosed` if `app.Shutdown` was called manually via interrupt signal(CTRL/CMD+C), note that if the server closed by any other reason the error will be fired as previously (unless `iris.WithoutServerError(iris.ErrServerClosed)`).
|
||||
|
||||
- Finally, Log level's and Route debug information colorization is respected across outputs. Previously if the application used more than one output destination (e.g. a file through `app.Logger().AddOutput`) the color support was automatically disabled from all, including the terminal one, this problem is fixed now. Developers can now see colors in their terminals while log files are kept with clear text.
|
||||
|
||||
- New `iris.WithLowercaseRouting` option which forces all routes' paths to be lowercase and converts request paths to their lowercase for matching.
|
||||
|
||||
@@ -4,5 +4,5 @@ go 1.13
|
||||
|
||||
require (
|
||||
github.com/betacraft/yaag v1.0.1-0.20191027021412-565f65e36090
|
||||
github.com/kataras/iris/v12 v12.1.5
|
||||
github.com/kataras/iris/v12 v12.1.8
|
||||
)
|
||||
|
||||
@@ -38,5 +38,5 @@ func main() {
|
||||
// http://localhost:8080
|
||||
// http://localhost:8080/ping
|
||||
// http://localhost:8080/hello
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
@@ -50,8 +50,6 @@ func main() {
|
||||
app.Run(
|
||||
// Start the web server at localhost:8080
|
||||
iris.Addr("localhost:8080"),
|
||||
// skip err server closed when CTRL/CMD+C pressed:
|
||||
iris.WithoutServerError(iris.ErrServerClosed),
|
||||
// enables faster json serialization and more:
|
||||
iris.WithOptimizations,
|
||||
)
|
||||
|
||||
@@ -32,8 +32,5 @@ func main() {
|
||||
// Path: http://localhost:8080
|
||||
app.Get("/", indexHandler)
|
||||
|
||||
app.Run(
|
||||
iris.Addr(":8080"),
|
||||
iris.WithoutServerError(iris.ErrServerClosed),
|
||||
)
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ func main() {
|
||||
app := iris.New()
|
||||
|
||||
iris.RegisterOnInterrupt(func() {
|
||||
timeout := 5 * time.Second
|
||||
timeout := 10 * time.Second
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
// close all hosts
|
||||
|
||||
@@ -33,7 +33,7 @@ func main() {
|
||||
case <-ch:
|
||||
println("shutdown...")
|
||||
|
||||
timeout := 5 * time.Second
|
||||
timeout := 10 * time.Second
|
||||
ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
|
||||
defer cancel()
|
||||
app.Shutdown(ctx)
|
||||
|
||||
@@ -18,7 +18,7 @@ func main() {
|
||||
app := iris.New()
|
||||
|
||||
iris.RegisterOnInterrupt(func() {
|
||||
timeout := 5 * time.Second
|
||||
timeout := 10 * time.Second
|
||||
ctx, cancel := stdContext.WithTimeout(stdContext.Background(), timeout)
|
||||
defer cancel()
|
||||
// close all hosts
|
||||
|
||||
@@ -17,7 +17,8 @@ func main() {
|
||||
}
|
||||
// same as:
|
||||
// err := app.Listen(":8080")
|
||||
// if err != nil && (err != iris.ErrServerClosed || err.Error() != iris.ErrServerClosed.Error()) {
|
||||
// import "errors"
|
||||
// if errors.Is(err, iris.ErrServerClosed) {
|
||||
// [...]
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -60,9 +60,8 @@ func TestListenAddrWithoutServerErr(t *testing.T) {
|
||||
app.Shutdown(ctx)
|
||||
}()
|
||||
|
||||
// we disable the ErrServerClosed, so the error should be nil when server is closed by `app.Shutdown`.
|
||||
|
||||
// so in this case the iris/http.ErrServerClosed should be NOT logged and NOT return.
|
||||
// we disable the ErrServerClosed, so the error should be nil when server is closed by `app.Shutdown`
|
||||
// or by an external issue.
|
||||
err := app.Listen(":9827", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
if err != nil {
|
||||
t.Fatalf("expecting err to be nil but got: %v", err)
|
||||
|
||||
@@ -11,14 +11,14 @@ func main() {
|
||||
app := iris.New()
|
||||
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.HTML("<h1>Hello, try to refresh the page after ~10 secs</h1>")
|
||||
ctx.HTML("<h1>Hello, try to refresh the page after ~5 secs</h1>")
|
||||
})
|
||||
|
||||
app.Logger().Info("Wait 10 seconds and check your terminal again")
|
||||
app.Logger().Info("Wait 5 seconds and check your terminal again")
|
||||
// simulate a shutdown action here...
|
||||
go func() {
|
||||
<-time.After(10 * time.Second)
|
||||
timeout := 5 * time.Second
|
||||
<-time.After(5 * time.Second)
|
||||
timeout := 10 * time.Second
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
// close all hosts, this will notify the callback we had register
|
||||
@@ -36,21 +36,24 @@ func main() {
|
||||
// wait 10 seconds and check your terminal.
|
||||
app.Run(iris.Addr(":8080", configureHost), iris.WithoutServerError(iris.ErrServerClosed))
|
||||
|
||||
/*
|
||||
Or for simple cases you can just use the:
|
||||
iris.RegisterOnInterrupt for global catch of the CTRL/CMD+C and OS events.
|
||||
Look at the "graceful-shutdown" example for more.
|
||||
time.Sleep(500 * time.Millisecond) // give time to the separate go routine(`onServerShutdown`) to finish.
|
||||
|
||||
/* See
|
||||
iris.RegisterOnInterrupt(callback) for global catch of the CTRL/CMD+C and OS events.
|
||||
Look at the "graceful-shutdown" example for more.
|
||||
*/
|
||||
}
|
||||
|
||||
func onServerShutdown() {
|
||||
println("server is closed")
|
||||
}
|
||||
|
||||
func configureHost(su *iris.Supervisor) {
|
||||
// here we have full access to the host that will be created
|
||||
// inside the `app.Run` function or `NewHost`.
|
||||
//
|
||||
// we're registering a shutdown "event" callback here:
|
||||
su.RegisterOnShutdown(func() {
|
||||
println("server is closed")
|
||||
})
|
||||
su.RegisterOnShutdown(onServerShutdown)
|
||||
// su.RegisterOnError
|
||||
// su.RegisterOnServe
|
||||
}
|
||||
|
||||
@@ -24,5 +24,5 @@ func main() {
|
||||
|
||||
// http://localhost:8080?referer=https://twitter.com/Xinterio/status/1023566830974251008
|
||||
// http://localhost:8080?referer=https://www.google.com/search?q=Top+6+golang+web+frameworks&oq=Top+6+golang+web+frameworks
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ func main() {
|
||||
//
|
||||
// The response should be:
|
||||
// Received: main.config{Addr:"localhost:8080", ServerName:"Iris"}
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed), iris.WithOptimizations)
|
||||
app.Listen(":8080", iris.WithOptimizations)
|
||||
}
|
||||
|
||||
func newApp() *iris.Application {
|
||||
|
||||
@@ -19,7 +19,7 @@ func main() {
|
||||
//
|
||||
// The response should be:
|
||||
// Received: main.config{Addr:"localhost:8080", ServerName:"Iris"}
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed), iris.WithOptimizations)
|
||||
app.Listen(":8080", iris.WithOptimizations)
|
||||
}
|
||||
|
||||
func newApp() *iris.Application {
|
||||
|
||||
@@ -60,5 +60,5 @@ func main() {
|
||||
//
|
||||
// The response should be:
|
||||
// Received: main.Company{Name:"iris-Go", City:"New York", Other:"Something here"}
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed), iris.WithOptimizations)
|
||||
app.Listen(":8080", iris.WithOptimizations)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ func main() {
|
||||
//
|
||||
// The response should be:
|
||||
// Received: main.person{XMLName:xml.Name{Space:"", Local:"person"}, Name:"Winston Churchill", Age:90, Description:"Description of this person, the body of this inner element."}
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed), iris.WithOptimizations)
|
||||
app.Listen(":8080", iris.WithOptimizations)
|
||||
}
|
||||
|
||||
func newApp() *iris.Application {
|
||||
|
||||
@@ -61,5 +61,5 @@ func main() {
|
||||
// http://localhost:8080/2
|
||||
// http://lcoalhost:8080/notfoundhere
|
||||
// see the output on the console.
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ func main() {
|
||||
// http://localhost:8080/1
|
||||
// http://localhost:8080/2
|
||||
// http://lcoalhost:8080/notfoundhere
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
var excludeExtensions = [...]string{
|
||||
|
||||
@@ -35,7 +35,7 @@ func main() {
|
||||
// http://localhost:8080/1
|
||||
// http://localhost:8080/2
|
||||
// http://lcoalhost:8080/notfoundhere
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
// get a filename based on the date, file logs works that way the most times
|
||||
|
||||
@@ -18,5 +18,5 @@ func main() {
|
||||
app := newApp()
|
||||
// http://localhost:8080
|
||||
// http://localhost:8080/yourname
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ func main() {
|
||||
})
|
||||
}() // ...
|
||||
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
/* For a golang SSE client you can look at: https://github.com/r3labs/sse#example-client */
|
||||
|
||||
@@ -187,5 +187,5 @@ func main() {
|
||||
|
||||
// http://localhost:8080
|
||||
// http://localhost:8080/events
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
@@ -113,5 +113,5 @@ func main() {
|
||||
//
|
||||
// `iris.WithoutServerError` is an optional configurator,
|
||||
// if passed to the `Run` then it will not print its passed error as an actual server error.
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed), iris.WithOptimizations)
|
||||
app.Listen(":8080", iris.WithOptimizations)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func main() {
|
||||
|
||||
// Navigate to http://localhost:8080/ping
|
||||
// and open the ./logs{TODAY}.txt file.
|
||||
if err := app.Listen(":8080", iris.WithoutBanner, iris.WithoutServerError(iris.ErrServerClosed)); err != nil {
|
||||
if err := app.Listen(":8080", iris.WithoutBanner); err != nil {
|
||||
app.Logger().Warn("Shutdown with error: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func main() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
resp, err := client.Post("https://localhost/hello", "application/json", buf)
|
||||
resp, err := client.Post("https://localhost/helloworld.Greeter/SayHello", "application/json", buf)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ func main() {
|
||||
app.Logger().SetLevel("debug")
|
||||
|
||||
// The Iris server should ran under TLS (it's a gRPC requirement).
|
||||
// POST: https://localhost:443/helloworld.greeter/sayhello
|
||||
// POST: https://localhost:443/helloworld.Greeter/SayHello
|
||||
// with request data: {"name": "John"}
|
||||
// and expected output: {"message": "Hello John"}
|
||||
app.Run(iris.TLS(":443", "server.crt", "server.key"))
|
||||
@@ -32,7 +32,6 @@ func main() {
|
||||
func newApp() *iris.Application {
|
||||
app := iris.New()
|
||||
// app.Configure(iris.WithLowercaseRouting) // OPTIONAL.
|
||||
app.Logger().SetLevel("debug")
|
||||
|
||||
app.Get("/", func(ctx iris.Context) {
|
||||
ctx.HTML("<h1>Index Page</h1>")
|
||||
@@ -55,7 +54,9 @@ func newApp() *iris.Application {
|
||||
return app
|
||||
}
|
||||
|
||||
type myController struct{}
|
||||
type myController struct {
|
||||
// Ctx iris.Context
|
||||
}
|
||||
|
||||
// SayHello implements helloworld.GreeterServer.
|
||||
func (c *myController) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
|
||||
|
||||
@@ -76,12 +76,8 @@ func main() {
|
||||
// http://localhost:8080/user/me
|
||||
// http://localhost:8080/user/logout
|
||||
// basic auth: "admin", "password", see "./middleware/basicauth.go" source file.
|
||||
app.Run(
|
||||
// Starts the web server at localhost:8080
|
||||
iris.Addr("localhost:8080"),
|
||||
// Ignores err server closed log when CTRL/CMD+C pressed.
|
||||
iris.WithoutServerError(iris.ErrServerClosed),
|
||||
// Enables faster json serialization and more.
|
||||
iris.WithOptimizations,
|
||||
)
|
||||
|
||||
// Starts the web server at localhost:8080
|
||||
// Enables faster json serialization and more.
|
||||
app.Listen(":8080", iris.WithOptimizations)
|
||||
}
|
||||
|
||||
@@ -30,14 +30,7 @@ func main() {
|
||||
// http://localhost:8080/hello/iris
|
||||
// http://localhost:8080/movies
|
||||
// http://localhost:8080/movies/1
|
||||
app.Run(
|
||||
// Start the web server at localhost:8080
|
||||
iris.Addr("localhost:8080"),
|
||||
// skip err server closed when CTRL/CMD+C pressed:
|
||||
iris.WithoutServerError(iris.ErrServerClosed),
|
||||
// enables faster json serialization and more:
|
||||
iris.WithOptimizations,
|
||||
)
|
||||
app.Listen(":8080", iris.WithOptimizations)
|
||||
}
|
||||
|
||||
// note the mvc.Application, it's not iris.Application.
|
||||
|
||||
@@ -165,7 +165,8 @@ func main() {
|
||||
"data": user.Serializer(),
|
||||
})
|
||||
})
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
type patchParam struct {
|
||||
|
||||
@@ -70,5 +70,5 @@ func main() {
|
||||
|
||||
// http://localhost:8080/insert
|
||||
// http://localhost:8080/get
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
@@ -98,5 +98,5 @@ func main() {
|
||||
myCustomRouter := new(customRouter)
|
||||
app.BuildRouter(app.ContextPool, myCustomRouter, app.APIBuilder, true)
|
||||
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func main() {
|
||||
// this will handle only GET "/other2/static"
|
||||
app.Get("/other2/static2", staticPathOther2)
|
||||
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
func h(ctx iris.Context) {
|
||||
|
||||
@@ -104,5 +104,5 @@ func main() {
|
||||
}
|
||||
})
|
||||
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
@@ -105,5 +105,5 @@ func main() {
|
||||
}
|
||||
})
|
||||
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ func main() {
|
||||
// POST, GET: http://localhost:8080/api/v1/topics
|
||||
// POST : http://localhost:8080/apiv1/topics/{topic}/produce?key=my-key
|
||||
// GET : http://localhost:8080/apiv1/topics/{topic}/consume?partition=0&offset=0 (these url query parameters are optional)
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
// simple use-case, you can use templates and views obviously, see the "_examples/views" examples.
|
||||
|
||||
@@ -116,5 +116,5 @@ func main() {
|
||||
// serves the npm browser websocket client usage example.
|
||||
app.HandleDir("/browserify", "./browserify")
|
||||
|
||||
app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
@@ -3,6 +3,6 @@ module github.com/kataras/iris/_examples/websocket/socketio
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/googollee/go-socket.io v1.4.3-0.20191109153049-7451e2f8c2e0 // indirect
|
||||
github.com/kataras/iris/v12 v12.1.5
|
||||
github.com/googollee/go-socket.io v1.4.3-0.20191109153049-7451e2f8c2e0
|
||||
github.com/kataras/iris/v12 v12.1.8
|
||||
)
|
||||
|
||||
@@ -47,10 +47,8 @@ func main() {
|
||||
|
||||
app.HandleMany("GET POST", "/socket.io/{any:path}", iris.FromStd(server))
|
||||
app.HandleDir("/", "./asset")
|
||||
app.Listen(":8000",
|
||||
iris.WithoutPathCorrection,
|
||||
iris.WithoutServerError(iris.ErrServerClosed),
|
||||
)
|
||||
|
||||
app.Listen(":8000", iris.WithoutPathCorrection)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -185,11 +185,8 @@ var WithGlobalConfiguration = func(app *Application) {
|
||||
app.Configure(WithConfiguration(YAML(globalConfigurationKeyword)))
|
||||
}
|
||||
|
||||
// variables for configurators don't need any receivers, functions
|
||||
// for them that need (helps code editors to recognise as variables without parenthesis completion).
|
||||
|
||||
// WithoutServerError will cause to ignore the matched "errors"
|
||||
// from the main application's `Run` function.
|
||||
// from the main application's `Run/Listen` function.
|
||||
//
|
||||
// Usage:
|
||||
// err := app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
stdContext "context"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
@@ -41,6 +42,10 @@ type Application interface {
|
||||
// It is ready to use after Build state.
|
||||
ServeHTTP(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
// Shutdown gracefully terminates all the application's server hosts and any tunnels.
|
||||
// Returns an error on the first failure, otherwise nil.
|
||||
Shutdown(ctx stdContext.Context) error
|
||||
|
||||
// GetRouteReadOnly returns the registered "read-only" route based on its name, otherwise nil.
|
||||
// One note: "routeName" should be case-sensitive. Used by the context to get the current route.
|
||||
// It returns an interface instead to reduce wrong usage and to keep the decoupled design between
|
||||
|
||||
@@ -27,11 +27,12 @@ type Configurator func(su *Supervisor)
|
||||
//
|
||||
// Interfaces are separated to return relative functionality to them.
|
||||
type Supervisor struct {
|
||||
Server *http.Server
|
||||
closedManually int32 // future use, accessed atomically (non-zero means we've called the Shutdown)
|
||||
manuallyTLS bool // we need that in order to determinate what to output on the console before the server begin.
|
||||
shouldWait int32 // non-zero means that the host should wait for unblocking
|
||||
unblockChan chan struct{}
|
||||
Server *http.Server
|
||||
closedManually uint32 // future use, accessed atomically (non-zero means we've called the Shutdown)
|
||||
closedByInterruptHandler uint32 // non-zero means that the end-developer interrupted it by-purpose.
|
||||
manuallyTLS bool // we need that in order to determinate what to output on the console before the server begin.
|
||||
shouldWait int32 // non-zero means that the host should wait for unblocking
|
||||
unblockChan chan struct{}
|
||||
|
||||
mu sync.Mutex
|
||||
|
||||
@@ -39,14 +40,11 @@ type Supervisor struct {
|
||||
// IgnoreErrors should contains the errors that should be ignored
|
||||
// on both serve functions return statements and error handlers.
|
||||
//
|
||||
// i.e: http.ErrServerClosed.Error().
|
||||
//
|
||||
// Note that this will match the string value instead of the equality of the type's variables.
|
||||
//
|
||||
// Defaults to empty.
|
||||
IgnoredErrors []string
|
||||
onErr []func(error)
|
||||
onShutdown []func()
|
||||
}
|
||||
|
||||
// New returns a new host supervisor
|
||||
@@ -143,6 +141,10 @@ func (su *Supervisor) validateErr(err error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if errors.Is(err, http.ErrServerClosed) && atomic.LoadUint32(&su.closedByInterruptHandler) > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
su.mu.Lock()
|
||||
defer su.mu.Unlock()
|
||||
|
||||
@@ -151,6 +153,7 @@ func (su *Supervisor) validateErr(err error) error {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -189,6 +192,8 @@ func (su *Supervisor) supervise(blockFunc func() error) error {
|
||||
host := createTaskHost(su)
|
||||
|
||||
su.notifyServe(host)
|
||||
atomic.StoreUint32(&su.closedByInterruptHandler, 0)
|
||||
atomic.StoreUint32(&su.closedManually, 0)
|
||||
|
||||
err := blockFunc()
|
||||
su.notifyErr(err)
|
||||
@@ -319,7 +324,7 @@ func (su *Supervisor) ListenAndServeAutoTLS(domain string, email string, cacheDi
|
||||
// supervisor in order to close the "secondary redirect server" as well.
|
||||
su.RegisterOnShutdown(func() {
|
||||
// give it some time to close itself...
|
||||
timeout := 5 * time.Second
|
||||
timeout := 10 * time.Second
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
srv2.Shutdown(ctx)
|
||||
@@ -346,21 +351,10 @@ func (su *Supervisor) ListenAndServeAutoTLS(domain string, email string, cacheDi
|
||||
// undergone NPN/ALPN protocol upgrade or that have been hijacked.
|
||||
// This function should start protocol-specific graceful shutdown,
|
||||
// but should not wait for shutdown to complete.
|
||||
//
|
||||
// Callbacks will run as separate go routines.
|
||||
func (su *Supervisor) RegisterOnShutdown(cb func()) {
|
||||
// when go1.9: replace the following lines with su.Server.RegisterOnShutdown(f)
|
||||
su.mu.Lock()
|
||||
su.onShutdown = append(su.onShutdown, cb)
|
||||
su.mu.Unlock()
|
||||
}
|
||||
|
||||
func (su *Supervisor) notifyShutdown() {
|
||||
// when go1.9: remove the lines below
|
||||
su.mu.Lock()
|
||||
for _, f := range su.onShutdown {
|
||||
go f()
|
||||
}
|
||||
su.mu.Unlock()
|
||||
// end
|
||||
su.Server.RegisterOnShutdown(cb)
|
||||
}
|
||||
|
||||
// Shutdown gracefully shuts down the server without interrupting any
|
||||
@@ -375,7 +369,11 @@ func (su *Supervisor) notifyShutdown() {
|
||||
// separately notify such long-lived connections of shutdown and wait
|
||||
// for them to close, if desired.
|
||||
func (su *Supervisor) Shutdown(ctx context.Context) error {
|
||||
atomic.AddInt32(&su.closedManually, 1) // future-use
|
||||
su.notifyShutdown()
|
||||
atomic.StoreUint32(&su.closedManually, 1) // future-use
|
||||
return su.Server.Shutdown(ctx)
|
||||
}
|
||||
|
||||
func (su *Supervisor) shutdownOnInterrupt(ctx context.Context) {
|
||||
atomic.StoreUint32(&su.closedByInterruptHandler, 1)
|
||||
su.Shutdown(ctx)
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ func ExampleSupervisor_RegisterOnServe() {
|
||||
logger := log.New(os.Stdout, "Supervisor: ", 0)
|
||||
|
||||
mytask := myTestTask{
|
||||
restartEvery: 6 * time.Second,
|
||||
restartEvery: 3 * time.Second,
|
||||
maxRestarts: 2,
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package host
|
||||
// supervisor.
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -27,8 +28,9 @@ func WriteStartupLogOnServe(w io.Writer) func(TaskHost) {
|
||||
if runtime.GOOS == "darwin" {
|
||||
interruptkey = "CMD"
|
||||
}
|
||||
_, _ = w.Write([]byte(fmt.Sprintf("Now listening on: %s\nApplication started. Press %s+C to shut down.\n",
|
||||
listeningURI, interruptkey)))
|
||||
|
||||
_, _ = fmt.Fprintf(w, "Now listening on: %s\nApplication started. Press %s+C to shut down.\n",
|
||||
listeningURI, interruptkey)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +40,7 @@ func ShutdownOnInterrupt(su *Supervisor, shutdownTimeout time.Duration) func() {
|
||||
return func() {
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), shutdownTimeout)
|
||||
defer cancel()
|
||||
su.Shutdown(ctx)
|
||||
su.shutdownOnInterrupt(ctx)
|
||||
su.RestoreFlow()
|
||||
}
|
||||
}
|
||||
@@ -58,9 +60,9 @@ func (h TaskHost) Serve() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// if http.serverclosed ignroe the error, it will have this error
|
||||
// if http.serverclosed ignore the error, it will have this error
|
||||
// from the previous close
|
||||
if err := h.Supervisor.Server.Serve(l); err != http.ErrServerClosed {
|
||||
if err := h.Supervisor.Server.Serve(l); !errors.Is(err, http.ErrServerClosed) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
4
iris.go
4
iris.go
@@ -668,8 +668,8 @@ func (app *Application) NewHost(srv *http.Server) *host.Supervisor {
|
||||
}
|
||||
|
||||
if !app.config.DisableInterruptHandler {
|
||||
// when CTRL+C/CMD+C pressed.
|
||||
shutdownTimeout := 5 * time.Second
|
||||
// when CTRL/CMD+C pressed.
|
||||
shutdownTimeout := 10 * time.Second
|
||||
host.RegisterOnInterrupt(host.ShutdownOnInterrupt(su, shutdownTimeout))
|
||||
// app.logger.Debugf("Host: register server shutdown on interrupt(CTRL+C/CMD+C)")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user