Added config options for http request timeouts
This commit is contained in:
@@ -16,6 +16,9 @@ type Config struct {
|
|||||||
Port string // Port to listen on
|
Port string // Port to listen on
|
||||||
TrustedHost string // Domain/Hostname to accept as trusted
|
TrustedHost string // Domain/Hostname to accept as trusted
|
||||||
SSL bool // Flag for SSL Mode
|
SSL bool // Flag for SSL Mode
|
||||||
|
ReadHeaderTimeout int // Timeout for reading request headers in seconds
|
||||||
|
WriteTimeout int // Timeout for writing requests in seconds
|
||||||
|
IdleTimeout int // Timeout for idle connections in seconds
|
||||||
TursoDBName string // DB Name for Turso DB/Branch
|
TursoDBName string // DB Name for Turso DB/Branch
|
||||||
TursoToken string // Bearer token for Turso DB/Branch
|
TursoToken string // Bearer token for Turso DB/Branch
|
||||||
SecretKey string // Secret key for signing tokens
|
SecretKey string // Secret key for signing tokens
|
||||||
@@ -81,6 +84,9 @@ func GetConfig(args map[string]string) (*Config, error) {
|
|||||||
Port: port,
|
Port: port,
|
||||||
TrustedHost: os.Getenv("TRUSTED_HOST"),
|
TrustedHost: os.Getenv("TRUSTED_HOST"),
|
||||||
SSL: GetEnvBool("SSL_MODE", false),
|
SSL: GetEnvBool("SSL_MODE", false),
|
||||||
|
ReadHeaderTimeout: GetEnvInt("READ_HEADER_TIMEOUT", 2),
|
||||||
|
WriteTimeout: GetEnvInt("WRITE_TIMEOUT", 10),
|
||||||
|
IdleTimeout: GetEnvInt("IDLE_TIMEOUT", 120),
|
||||||
TursoDBName: os.Getenv("TURSO_DB_NAME"),
|
TursoDBName: os.Getenv("TURSO_DB_NAME"),
|
||||||
TursoToken: os.Getenv("TURSO_AUTH_TOKEN"),
|
TursoToken: os.Getenv("TURSO_AUTH_TOKEN"),
|
||||||
SecretKey: os.Getenv("SECRET_KEY"),
|
SecretKey: os.Getenv("SECRET_KEY"),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Get an environment variable, specifying a default value if its not set
|
// Get an environment variable, specifying a default value if its not set
|
||||||
@@ -15,6 +16,38 @@ func GetEnvDefault(key string, defaultValue string) string {
|
|||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get an environment variable as a time.Duration, specifying a default value if its
|
||||||
|
// not set or can't be parsed properly
|
||||||
|
func GetEnvDur(key string, defaultValue time.Duration) time.Duration {
|
||||||
|
val, exists := os.LookupEnv(key)
|
||||||
|
if !exists {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
intVal, err := strconv.Atoi(val)
|
||||||
|
if err != nil {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
return time.Duration(intVal)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get an environment variable as an int, specifying a default value if its
|
||||||
|
// not set or can't be parsed properly into an int
|
||||||
|
func GetEnvInt(key string, defaultValue int) int {
|
||||||
|
val, exists := os.LookupEnv(key)
|
||||||
|
if !exists {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
intVal, err := strconv.Atoi(val)
|
||||||
|
if err != nil {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
return intVal
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Get an environment variable as an int64, specifying a default value if its
|
// Get an environment variable as an int64, specifying a default value if its
|
||||||
// not set or can't be parsed properly into an int64
|
// not set or can't be parsed properly into an int64
|
||||||
func GetEnvInt64(key string, defaultValue int64) int64 {
|
func GetEnvInt64(key string, defaultValue int64) int64 {
|
||||||
|
|||||||
@@ -8,4 +8,5 @@ func (c contextKey) String() string {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
contextKeyAuthorizedUser = contextKey("auth-user")
|
contextKeyAuthorizedUser = contextKey("auth-user")
|
||||||
|
contextKeyRequestTime = contextKey("req-time")
|
||||||
)
|
)
|
||||||
|
|||||||
21
contexts/request_timer.go
Normal file
21
contexts/request_timer.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package contexts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Set the start time of the request
|
||||||
|
func SetStart(ctx context.Context, time time.Time) context.Context {
|
||||||
|
return context.WithValue(ctx, contextKeyRequestTime, time)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the start time of the request
|
||||||
|
func GetStartTime(ctx context.Context) (time.Time, error) {
|
||||||
|
start, ok := ctx.Value(contextKeyRequestTime).(time.Time)
|
||||||
|
if !ok {
|
||||||
|
return time.Time{}, errors.New("Failed to get start time of request")
|
||||||
|
}
|
||||||
|
return start, nil
|
||||||
|
}
|
||||||
6
main.go
6
main.go
@@ -66,9 +66,9 @@ func run(ctx context.Context, w io.Writer, args map[string]string) error {
|
|||||||
httpServer := &http.Server{
|
httpServer := &http.Server{
|
||||||
Addr: net.JoinHostPort(config.Host, config.Port),
|
Addr: net.JoinHostPort(config.Host, config.Port),
|
||||||
Handler: srv,
|
Handler: srv,
|
||||||
ReadHeaderTimeout: 2 * time.Second,
|
ReadHeaderTimeout: config.ReadHeaderTimeout * time.Second,
|
||||||
WriteTimeout: 10 * time.Second,
|
WriteTimeout: config.WriteTimeout * time.Second,
|
||||||
IdleTimeout: 120 * time.Second,
|
IdleTimeout: config.IdleTimeout * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runs function for testing in dev if --test flag true
|
// Runs function for testing in dev if --test flag true
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package middleware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"projectreshoot/contexts"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
@@ -22,7 +23,11 @@ func (w *wrappedWriter) WriteHeader(statusCode int) {
|
|||||||
// Middleware to add logs to console with details of the request
|
// Middleware to add logs to console with details of the request
|
||||||
func Logging(logger *zerolog.Logger, next http.Handler) http.Handler {
|
func Logging(logger *zerolog.Logger, next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
start := time.Now()
|
start, err := contexts.GetStartTime(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
// Handle failure here. internal server error maybe
|
||||||
|
return
|
||||||
|
}
|
||||||
wrapped := &wrappedWriter{
|
wrapped := &wrappedWriter{
|
||||||
ResponseWriter: w,
|
ResponseWriter: w,
|
||||||
statusCode: http.StatusOK,
|
statusCode: http.StatusOK,
|
||||||
|
|||||||
18
middleware/start.go
Normal file
18
middleware/start.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"projectreshoot/contexts"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func StartTimer(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(
|
||||||
|
func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
start := time.Now()
|
||||||
|
ctx := contexts.SetStart(r.Context(), start)
|
||||||
|
newReq := r.WithContext(ctx)
|
||||||
|
next.ServeHTTP(w, newReq)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -32,5 +32,8 @@ func NewServer(
|
|||||||
// Serve the favicon and exluded files before any middleware is added
|
// Serve the favicon and exluded files before any middleware is added
|
||||||
handler = middleware.ExcludedFiles(handler)
|
handler = middleware.ExcludedFiles(handler)
|
||||||
handler = middleware.Favicon(handler)
|
handler = middleware.Favicon(handler)
|
||||||
|
|
||||||
|
// Start the timer for the request chain so logger can have accurate info
|
||||||
|
handler = middleware.StartTimer(handler)
|
||||||
return handler
|
return handler
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user