Add a timeout middleware to the server
This commit is contained in:
parent
d53afa4903
commit
bfdf7bf7d2
24
cmd/start.go
24
cmd/start.go
@ -3,6 +3,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"git.coopcloud.tech/wiki-cafe/member-console/internal/auth"
|
"git.coopcloud.tech/wiki-cafe/member-console/internal/auth"
|
||||||
"git.coopcloud.tech/wiki-cafe/member-console/internal/middleware"
|
"git.coopcloud.tech/wiki-cafe/member-console/internal/middleware"
|
||||||
@ -36,18 +37,23 @@ var startCmd = &cobra.Command{
|
|||||||
|
|
||||||
// Create middleware stack
|
// Create middleware stack
|
||||||
stack := middleware.CreateStack(
|
stack := middleware.CreateStack(
|
||||||
middleware.Recovery(), // Add recovery middleware first to catch all panics
|
middleware.Recovery(), // Catch all panics
|
||||||
middleware.RequestID(), // Add request ID middleware for tracing
|
middleware.TimeoutMiddleware(32*time.Second), // Set request timeout
|
||||||
middleware.SecureHeaders,
|
middleware.RequestID(), // Generate a unique request ID
|
||||||
middleware.Logging,
|
middleware.MaxBodySize(1024*1024), // 1MB size limit
|
||||||
middleware.MaxBodySize(1024*1024), // 1MB size limit
|
middleware.SecureHeaders, // Set secure headers
|
||||||
authConfig.Middleware(),
|
middleware.Logging, // Log requests
|
||||||
|
authConfig.Middleware(), // OIDC authentication middleware
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create HTTP server
|
// Create HTTP server
|
||||||
server := http.Server{
|
server := http.Server{
|
||||||
Addr: ":" + port,
|
Addr: ":" + port,
|
||||||
Handler: stack(httpRequestRouter),
|
Handler: stack(httpRequestRouter),
|
||||||
|
ReadTimeout: 2 * time.Second,
|
||||||
|
WriteTimeout: 4 * time.Second,
|
||||||
|
IdleTimeout: 8 * time.Second,
|
||||||
|
MaxHeaderBytes: 1024 * 1024, // 1MB
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serve the components directory
|
// Serve the components directory
|
||||||
@ -76,4 +82,4 @@ func init() {
|
|||||||
|
|
||||||
// Add the command to the root command
|
// Add the command to the root command
|
||||||
rootCmd.AddCommand(startCmd)
|
rootCmd.AddCommand(startCmd)
|
||||||
}
|
}
|
||||||
|
46
internal/middleware/timeout.go
Normal file
46
internal/middleware/timeout.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TimeoutMiddleware is necessary in addition to http.Server's ReadTimeout,
|
||||||
|
// WriteTimeout, and IdleTimeout. http.Server's timeouts are network-level
|
||||||
|
// timeouts, while this middleware's timeout is at the application level.
|
||||||
|
// TODO: Verify this statement
|
||||||
|
|
||||||
|
// TimeoutMiddleware sets a timeout for each request
|
||||||
|
func TimeoutMiddleware(duration time.Duration) Middleware {
|
||||||
|
return func(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Create a context with a timeout
|
||||||
|
ctx, cancel := context.WithTimeout(r.Context(), duration)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Create a channel to signal when the request is done
|
||||||
|
done := make(chan struct{})
|
||||||
|
|
||||||
|
// Create a new request with the timeout context
|
||||||
|
r = r.WithContext(ctx)
|
||||||
|
|
||||||
|
// Use a goroutine to run the next handler
|
||||||
|
go func() {
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for the handler to finish or the context to timeout
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
// Request finished within the timeout
|
||||||
|
return
|
||||||
|
case <-ctx.Done():
|
||||||
|
// Timeout occurred, respond with a timeout error
|
||||||
|
http.Error(w, "Request timed out", http.StatusGatewayTimeout)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user