Documentation
¶
Overview ¶
Package timeout provides request timeout middleware for celeris.
The middleware wraps each request's context with a deadline. If the downstream handler does not complete before the deadline, the context is cancelled and a configurable error response is returned.
Basic usage with the default 5-second timeout:
server.Use(timeout.New())
Custom timeout and error handler:
server.Use(timeout.New(timeout.Config{
Timeout: 10 * time.Second,
ErrorHandler: func(c *celeris.Context, err error) error {
return c.JSON(503, map[string]string{"error": "timed out"})
},
}))
Set Config.Preemptive to true to run the handler in a separate goroutine with response buffering. In preemptive mode, the middleware returns the timeout error immediately when the deadline expires, even if the handler is blocked on a non-context-aware operation.
Set Config.TimeoutFunc to compute a timeout dynamically per request. The static Config.Timeout is used as a fallback when TimeoutFunc is nil or returns a non-positive duration.
In cooperative mode (default), the handler runs in the request goroutine. The context deadline is set, but the handler must check c.Context().Done() to respect the timeout. Cooperative mode has no extra goroutine overhead and no response buffering cost.
Config.ErrorHandler receives the triggering error (context.DeadlineExceeded, a matched TimeoutErrors entry, or a panic-wrapped error). If it panics, ErrServiceUnavailable is returned as a last-resort fallback.
Config.TimeoutErrors lists errors that should be treated as timeouts even if the deadline has not been reached (e.g., database query timeouts).
ErrServiceUnavailable is the exported sentinel error (503) returned when no custom error handler is configured, usable with errors.Is.
Set Config.Skip to bypass the middleware dynamically, or Config.SkipPaths for exact-match path exclusions.
Warning: In preemptive mode, if the handler does not exit promptly after context cancellation, the middleware goroutine blocks waiting for the handler to complete. This ties up the connection and prevents the Context from being returned to the pool. Handlers MUST check c.Context().Done() and return quickly on cancellation.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
ErrServiceUnavailable is returned when the request timeout is exceeded.
Functions ¶
func New ¶
func New(config ...Config) celeris.HandlerFunc
New creates a timeout middleware with the given config.
Example ¶
package main
import (
"github.com/goceleris/middlewares/timeout"
)
func main() {
// Zero-config: 5-second cooperative timeout.
_ = timeout.New()
}
Output:
Example (CustomErrorHandler) ¶
package main
import (
"time"
"github.com/goceleris/celeris"
"github.com/goceleris/middlewares/timeout"
)
func main() {
// Custom error handler that receives the timeout cause.
_ = timeout.New(timeout.Config{
Timeout: 10 * time.Second,
ErrorHandler: func(c *celeris.Context, err error) error {
return c.JSON(503, map[string]string{"error": err.Error()})
},
})
}
Output:
Example (Preemptive) ¶
package main
import (
"time"
"github.com/goceleris/middlewares/timeout"
)
func main() {
// Preemptive timeout: returns 503 even if handler is blocked.
// Handlers MUST check c.Context().Done() for prompt cancellation.
_ = timeout.New(timeout.Config{
Timeout: 3 * time.Second,
Preemptive: true,
})
}
Output:
Types ¶
type Config ¶
type Config struct {
// Skip defines a function to skip this middleware for certain requests.
Skip func(c *celeris.Context) bool
// Timeout is the request timeout duration. Default: 5s.
// Used as the fallback when TimeoutFunc is nil or returns zero.
Timeout time.Duration
// TimeoutFunc computes a per-request timeout duration. When non-nil,
// its return value is used instead of the static Timeout. If it
// returns zero or a negative duration, the static Timeout is used
// as a fallback.
//
// TimeoutFunc is called before BufferResponse in preemptive mode,
// so it runs on the request goroutine (not the handler goroutine).
TimeoutFunc func(c *celeris.Context) time.Duration
// ErrorHandler handles timeout errors. The err parameter is
// context.DeadlineExceeded for a deadline timeout, the matched
// TimeoutErrors entry for a semantic timeout, or a panic-wrapped error
// for a recovered panic. Default: returns 503 Service Unavailable.
ErrorHandler func(c *celeris.Context, err error) error
// SkipPaths lists paths to skip (exact match).
SkipPaths []string
// Preemptive enables preemptive timeout mode. When true, the handler
// runs in a goroutine and the response is buffered. If the handler
// does not complete within the timeout, the middleware waits for the
// goroutine to finish, discards the buffered response, and returns
// the error handler result. Handlers MUST respect context cancellation
// (select on c.Context().Done()) to avoid blocking the response.
Preemptive bool
// TimeoutErrors lists errors that should be treated as timeouts even
// if the deadline has not been reached. When the handler returns an
// error matching any entry via errors.Is, the ErrorHandler is invoked
// as though the request timed out. This is useful for treating
// upstream timeout errors (e.g. database query timeout) as request
// timeouts.
TimeoutErrors []error
}
Config defines the timeout middleware configuration.