mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 02:31:04 +01:00
new Timeout, TimeoutMessage configuration fields and apps.OnApplicationRegistered listener
This commit is contained in:
parent
968a9ec06c
commit
d6cfe3fe5b
|
@ -28,6 +28,10 @@ The codebase for Dependency Injection, Internationalization and localization and
|
|||
|
||||
## Fixes and Improvements
|
||||
|
||||
- New `Configuration.Timeout` and `Configuration.TimeoutMessage` fields. Use it to set HTTP timeouts. Note that your http server's (`Application.ConfigureHost`) Read/Write timeouts should be a bit higher than the `Configuration.Timeout` in order to give some time to http timeout handler to kick in and be able to send the `Configuration.TimeoutMessage` properly.
|
||||
|
||||
- New `apps.OnApplicationRegistered` method which listens on new Iris applications hosted under the same binary. Use it on your `init` functions to configure Iris applications by any spot in your project's files.
|
||||
|
||||
- `Context.JSON` respects any object implements the `easyjson.Marshaler` interface and renders the result using the [easyjon](https://github.com/mailru/easyjson)'s writer.
|
||||
|
||||
- minor: `Context` structure implements the standard go Context interface now (includes: Deadline, Done, Err and Value methods). Handlers can now just pass the `ctx iris.Context` as a shortcut of `ctx.Request().Context()` when needed.
|
||||
|
|
12
apps/apps.go
12
apps/apps.go
|
@ -48,3 +48,15 @@ func GetAll() []*iris.Application {
|
|||
|
||||
return apps
|
||||
}
|
||||
|
||||
// OnApplicationRegistered adds a function which fires when a new application
|
||||
// is registered.
|
||||
func OnApplicationRegistered(listeners ...func(app *iris.Application)) {
|
||||
appListeners := make([]func(context.Application), 0, len(listeners))
|
||||
for i := range listeners {
|
||||
appListeners = append(appListeners, func(ctxApp context.Application) {
|
||||
listeners[i](ctxApp.(*iris.Application))
|
||||
})
|
||||
}
|
||||
context.OnApplicationRegistered(appListeners...)
|
||||
}
|
||||
|
|
|
@ -208,6 +208,14 @@ func WithKeepAlive(keepAliveDur time.Duration) Configurator {
|
|||
}
|
||||
}
|
||||
|
||||
// WithTimeout sets the `Configuration.Timeout` field to the given duration.
|
||||
func WithTimeout(timeoutDur time.Duration, htmlBody string) Configurator {
|
||||
return func(app *Application) {
|
||||
app.config.Timeout = timeoutDur
|
||||
app.config.TimeoutMessage = htmlBody
|
||||
}
|
||||
}
|
||||
|
||||
// WithoutServerError will cause to ignore the matched "errors"
|
||||
// from the main application's `Run/Listen` function.
|
||||
//
|
||||
|
@ -498,7 +506,6 @@ func WithSitemap(startURL string) Configurator {
|
|||
} else {
|
||||
href = "/" + langPath + loc
|
||||
}
|
||||
|
||||
} else if app.I18n.Subdomain {
|
||||
// then use the subdomain.
|
||||
// e.g. http://el.domain.com/path
|
||||
|
@ -627,6 +634,17 @@ type Configuration struct {
|
|||
//
|
||||
// Defaults to 0.
|
||||
KeepAlive time.Duration `ini:"keepalive" json:"keepAlive" yaml:"KeepAlive" toml:"KeepAlive" env:"KEEP_ALIVE"`
|
||||
// Timeout wraps the application's router with an http timeout handler
|
||||
// if the value is greater than zero.
|
||||
//
|
||||
// The underline response writer supports the Pusher interface but does not support
|
||||
// the Hijacker or Flusher interfaces when Timeout handler is registered.
|
||||
//
|
||||
// Read more at: https://pkg.go.dev/net/http#TimeoutHandler.
|
||||
Timeout time.Duration `ini:"timeout" json:"timeout" yaml:"Timeout" toml:"Timeout"`
|
||||
// TimeoutMessage specifies the HTML body when a handler hits its life time based
|
||||
// on the Timeout configuration field.
|
||||
TimeoutMessage string `ini:"timeout_message" json:"timeoutMessage" yaml:"TimeoutMessage" toml:"TimeoutMessage"`
|
||||
// Tunneling can be optionally set to enable ngrok http(s) tunneling for this Iris app instance.
|
||||
// See the `WithTunneling` Configurator too.
|
||||
Tunneling TunnelingConfiguration `ini:"tunneling" json:"tunneling,omitempty" yaml:"Tunneling" toml:"Tunneling"`
|
||||
|
@ -914,6 +932,16 @@ func (c Configuration) GetKeepAlive() time.Duration {
|
|||
return c.KeepAlive
|
||||
}
|
||||
|
||||
// GetKeepAlive returns the Timeout field.
|
||||
func (c Configuration) GetTimeout() time.Duration {
|
||||
return c.Timeout
|
||||
}
|
||||
|
||||
// GetKeepAlive returns the TimeoutMessage field.
|
||||
func (c Configuration) GetTimeoutMessage() string {
|
||||
return c.TimeoutMessage
|
||||
}
|
||||
|
||||
// GetDisablePathCorrection returns the DisablePathCorrection field.
|
||||
func (c Configuration) GetDisablePathCorrection() bool {
|
||||
return c.DisablePathCorrection
|
||||
|
@ -1088,6 +1116,14 @@ func WithConfiguration(c Configuration) Configurator {
|
|||
main.KeepAlive = v
|
||||
}
|
||||
|
||||
if v := c.Timeout; v > 0 {
|
||||
main.Timeout = v
|
||||
}
|
||||
|
||||
if v := c.TimeoutMessage; v != "" {
|
||||
main.TimeoutMessage = v
|
||||
}
|
||||
|
||||
if len(c.Tunneling.Tunnels) > 0 {
|
||||
main.Tunneling = c.Tunneling
|
||||
}
|
||||
|
@ -1234,12 +1270,18 @@ func WithConfiguration(c Configuration) Configurator {
|
|||
}
|
||||
}
|
||||
|
||||
// DefaultTimeoutMessage is the default timeout message which is rendered
|
||||
// on expired handlers when timeout handler is registered (see Timeout configuration field).
|
||||
var DefaultTimeoutMessage = `<html><head><title>Timeout</title></head><body><h1>Timeout</h1>Looks like the server is taking too long to respond, this can be caused by either poor connectivity or an error with our servers. Please try again in a while.</body></html>`
|
||||
|
||||
// DefaultConfiguration returns the default configuration for an iris station, fills the main Configuration
|
||||
func DefaultConfiguration() Configuration {
|
||||
return Configuration{
|
||||
LogLevel: "info",
|
||||
SocketSharding: false,
|
||||
KeepAlive: 0,
|
||||
Timeout: 0,
|
||||
TimeoutMessage: DefaultTimeoutMessage,
|
||||
DisableStartupLog: false,
|
||||
DisableInterruptHandler: false,
|
||||
DisablePathCorrection: false,
|
||||
|
|
|
@ -113,8 +113,9 @@ var (
|
|||
// It's slice instead of map because if IRIS_APP_NAME env var exists,
|
||||
// by-default all applications running on the same machine
|
||||
// will have the same name unless `Application.SetName` is called.
|
||||
registeredApps []Application
|
||||
mu sync.RWMutex
|
||||
registeredApps []Application
|
||||
onApplicationRegisteredListeners []func(Application)
|
||||
mu sync.RWMutex
|
||||
)
|
||||
|
||||
// RegisterApplication registers an application to the global shared storage.
|
||||
|
@ -126,6 +127,20 @@ func RegisterApplication(app Application) {
|
|||
mu.Lock()
|
||||
registeredApps = append(registeredApps, app)
|
||||
mu.Unlock()
|
||||
|
||||
mu.RLock()
|
||||
for _, listener := range onApplicationRegisteredListeners {
|
||||
listener(app)
|
||||
}
|
||||
mu.RUnlock()
|
||||
}
|
||||
|
||||
// OnApplicationRegistered adds a function which fires when a new application
|
||||
// is registered.
|
||||
func OnApplicationRegistered(listeners ...func(app Application)) {
|
||||
mu.Lock()
|
||||
onApplicationRegisteredListeners = append(onApplicationRegisteredListeners, listeners...)
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
// GetApplications returns a slice of all the registered Applications.
|
||||
|
|
|
@ -20,6 +20,10 @@ type ConfigurationReadOnly interface {
|
|||
GetSocketSharding() bool
|
||||
// GetKeepAlive returns the KeepAlive field.
|
||||
GetKeepAlive() time.Duration
|
||||
// GetKeepAlive returns the Timeout field.
|
||||
GetTimeout() time.Duration
|
||||
// GetKeepAlive returns the TimeoutMessage field.
|
||||
GetTimeoutMessage() string
|
||||
// GetDisablePathCorrection returns the DisablePathCorrection field
|
||||
GetDisablePathCorrection() bool
|
||||
// GetDisablePathCorrectionRedirection returns the DisablePathCorrectionRedirection field.
|
||||
|
|
|
@ -708,7 +708,6 @@ func (ctx *Context) StopExecution() {
|
|||
// And stop.
|
||||
ctx.currentHandlerIndex = stopExecutionIndex
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// IsStopped reports whether the current position of the context's handlers is -1,
|
||||
|
@ -2697,7 +2696,6 @@ func (ctx *Context) ReadMsgPack(ptr interface{}) error {
|
|||
// As a special case if the "ptr" was a pointer to string or []byte
|
||||
// then it will bind it to the request body as it is.
|
||||
func (ctx *Context) ReadBody(ptr interface{}) error {
|
||||
|
||||
// If the ptr is string or byte, read the body as it's.
|
||||
switch v := ptr.(type) {
|
||||
case *string:
|
||||
|
@ -4871,7 +4869,6 @@ func CookieAllowReclaim(cookieNames ...string) CookieOption {
|
|||
header.Del("Cookie")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// CookieAllowSubdomains set to the Cookie Options
|
||||
|
@ -5888,5 +5885,12 @@ func (ctx *Context) GetID() interface{} {
|
|||
// It returns the Context's ID given by a `SetID`call,
|
||||
// followed by the client's IP and the method:uri.
|
||||
func (ctx *Context) String() string {
|
||||
return fmt.Sprintf("[%s] %s ▶ %s:%s", ctx.GetID(), ctx.RemoteAddr(), ctx.Method(), ctx.Request().RequestURI)
|
||||
id := ctx.GetID()
|
||||
if id != nil {
|
||||
if stringer, ok := id.(fmt.Stringer); ok {
|
||||
id = stringer.String()
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("[%v] %s ▶ %s:%s", id, ctx.RemoteAddr(), ctx.Method(), ctx.Request().RequestURI)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
|
||||
|
@ -271,6 +272,25 @@ func (router *Router) Downgraded() bool {
|
|||
return router.mainHandler != nil && router.requestHandler == nil
|
||||
}
|
||||
|
||||
// SetTimeoutHandler overrides the main handler with a timeout handler.
|
||||
//
|
||||
// TimeoutHandler supports the Pusher interface but does not support
|
||||
// the Hijacker or Flusher interfaces.
|
||||
//
|
||||
// All previous registered wrappers and middlewares are still executed as expected.
|
||||
func (router *Router) SetTimeoutHandler(timeout time.Duration, msg string) {
|
||||
if timeout <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
mainHandler := router.mainHandler
|
||||
h := func(w http.ResponseWriter, r *http.Request) {
|
||||
mainHandler(w, r)
|
||||
}
|
||||
|
||||
router.mainHandler = http.TimeoutHandler(http.HandlerFunc(h), timeout, msg).ServeHTTP
|
||||
}
|
||||
|
||||
// WrapRouter adds a wrapper on the top of the main router.
|
||||
// Usually it's useful for third-party middleware
|
||||
// when need to wrap the entire application with a middleware like CORS.
|
||||
|
|
5
iris.go
5
iris.go
|
@ -640,6 +640,11 @@ func (app *Application) Build() error {
|
|||
return err
|
||||
}
|
||||
app.HTTPErrorHandler = routerHandler
|
||||
|
||||
if app.config.Timeout > 0 {
|
||||
app.Router.SetTimeoutHandler(app.config.Timeout, app.config.TimeoutMessage)
|
||||
}
|
||||
|
||||
// re-build of the router from outside can be done with
|
||||
// app.RefreshRouter()
|
||||
}
|
||||
|
|
|
@ -12,6 +12,17 @@ import (
|
|||
|
||||
func init() {
|
||||
context.SetHandlerName("iris/middleware/pprof.*", "iris.profiling")
|
||||
|
||||
/* for our readers:
|
||||
apps.OnApplicationRegistered(func(app *iris.Application) {
|
||||
app.Any("/debug/pprof/cmdline", iris.FromStd(pprof.Cmdline))
|
||||
app.Any("/debug/pprof/profile", iris.FromStd(pprof.Profile))
|
||||
app.Any("/debug/pprof/symbol", iris.FromStd(pprof.Symbol))
|
||||
app.Any("/debug/pprof/trace", iris.FromStd(pprof.Trace))
|
||||
|
||||
app.Any("/debug/pprof /debug/pprof/{action:string}", New())
|
||||
})
|
||||
*/
|
||||
}
|
||||
|
||||
// net/http/pprof copy:
|
||||
|
|
Loading…
Reference in New Issue
Block a user