Documentation
¶
Overview ¶
Package timeout provides request timeout middleware for celeris.
New returns a celeris.HandlerFunc that wraps each request's context with a deadline. If the downstream handler does not complete within the configured duration, the context is cancelled and a configurable error response is returned.
Key exported symbols:
- New — constructs the middleware from a Config.
- Config — options: Config.Timeout (static duration, default 5 s), Config.TimeoutFunc (per-request duration; overrides Timeout when > 0), Config.ErrorHandler (called on timeout; default returns 503), Config.TimeoutErrors (treat matching upstream errors as timeouts), Config.Preemptive (run handler in a goroutine; see below), Config.Skip / Config.SkipPaths (bypass the middleware).
- ErrServiceUnavailable — sentinel 503 error; aliases celeris.ErrServiceUnavailable for cross-middleware errors.Is matching.
Cooperative mode (default, Preemptive: false): the handler runs in the request goroutine with the context deadline set. Handlers must observe c.Context().Done() to respect the cancellation. No goroutine or buffer overhead.
Preemptive mode (Preemptive: true): the handler runs in a spawned goroutine with the response buffered. When the deadline expires the middleware waits for the goroutine to exit, discards the buffered response, and invokes the error handler. Handlers MUST exit promptly on context cancellation to avoid blocking the connection. Incompatible with streaming (StreamWriter).
Documentation ¶
Full guides and examples: https://goceleris.dev/docs/middleware-traffic
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
ErrServiceUnavailable is returned when the request timeout is exceeded. ErrServiceUnavailable aliases celeris.ErrServiceUnavailable so callers can match across timeout/circuitbreaker/ratelimit with errors.Is.
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/celeris/middleware/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/celeris/middleware/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/celeris/middleware/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 mode is incompatible with StreamWriter: buffered mode
// captures the full response in memory, defeating streaming and
// potentially causing OOM on large payloads. Use non-preemptive
// mode (the default) for streaming endpoints.
//
// Cost: preemptive mode allocates a goroutine and a context.WithTimeout
// per request — measurable at very high RPS (~1-3% throughput on
// the reference benchmark suite). Reach for it only when you
// genuinely need to interrupt CPU-bound or blocking handlers; the
// non-preemptive default uses a single context.WithTimeout and lets
// handlers cooperatively check c.Context().Done().
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.