Enhance graceful shutdown and logging for HTTP server
- Implemented graceful shutdown for the HTTP server, allowing for a controlled shutdown process with a timeout. - Added logging for shutdown signals and server exit to improve traceability during application termination. - Introduced IP blacklist configuration to enhance security by blocking specified IP addresses. - Updated database cache configurations to allow dynamic adjustment via environment variables for better performance tuning.
This commit is contained in:
@@ -31,12 +31,15 @@ type C struct {
|
||||
EnableShutdown bool `env:"ORLY_ENABLE_SHUTDOWN" default:"false" usage:"if true, expose /shutdown on the health port to gracefully stop the process (for profiling)"`
|
||||
LogLevel string `env:"ORLY_LOG_LEVEL" default:"info" usage:"relay log level: fatal error warn info debug trace"`
|
||||
DBLogLevel string `env:"ORLY_DB_LOG_LEVEL" default:"info" usage:"database log level: fatal error warn info debug trace"`
|
||||
DBBlockCacheMB int `env:"ORLY_DB_BLOCK_CACHE_MB" default:"512" usage:"Badger block cache size in MB (higher improves read hit ratio)"`
|
||||
DBIndexCacheMB int `env:"ORLY_DB_INDEX_CACHE_MB" default:"256" usage:"Badger index cache size in MB (improves index lookup performance)"`
|
||||
LogToStdout bool `env:"ORLY_LOG_TO_STDOUT" default:"false" usage:"log to stdout instead of stderr"`
|
||||
Pprof string `env:"ORLY_PPROF" usage:"enable pprof in modes: cpu,memory,allocation,heap,block,goroutine,threadcreate,mutex"`
|
||||
PprofPath string `env:"ORLY_PPROF_PATH" usage:"optional directory to write pprof profiles into (inside container); default is temporary dir"`
|
||||
PprofHTTP bool `env:"ORLY_PPROF_HTTP" default:"false" usage:"if true, expose net/http/pprof on port 6060"`
|
||||
OpenPprofWeb bool `env:"ORLY_OPEN_PPROF_WEB" default:"false" usage:"if true, automatically open the pprof web viewer when profiling is enabled"`
|
||||
IPWhitelist []string `env:"ORLY_IP_WHITELIST" usage:"comma-separated list of IP addresses to allow access from, matches on prefixes to allow private subnets, eg 10.0.0 = 10.0.0.0/8"`
|
||||
IPBlacklist []string `env:"ORLY_IP_BLACKLIST" usage:"comma-separated list of IP addresses to block; matches on prefixes to allow subnets, e.g. 192.168 = 192.168.0.0/16"`
|
||||
Admins []string `env:"ORLY_ADMINS" usage:"comma-separated list of admin npubs"`
|
||||
Owners []string `env:"ORLY_OWNERS" usage:"comma-separated list of owner npubs, who have full control of the relay for wipe and restart and other functions"`
|
||||
ACLMode string `env:"ORLY_ACL_MODE" usage:"ACL mode: follows, managed (nip-86), none" default:"none"`
|
||||
|
||||
39
app/main.go
39
app/main.go
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"lol.mleku.dev/chk"
|
||||
"lol.mleku.dev/log"
|
||||
@@ -18,11 +20,14 @@ import (
|
||||
func Run(
|
||||
ctx context.Context, cfg *config.C, db *database.D,
|
||||
) (quit chan struct{}) {
|
||||
quit = make(chan struct{})
|
||||
var once sync.Once
|
||||
|
||||
// shutdown handler
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
log.I.F("shutting down")
|
||||
close(quit)
|
||||
once.Do(func() { close(quit) })
|
||||
}()
|
||||
// get the admins
|
||||
var err error
|
||||
@@ -112,9 +117,37 @@ func Run(
|
||||
}
|
||||
addr := fmt.Sprintf("%s:%d", cfg.Listen, cfg.Port)
|
||||
log.I.F("starting listener on http://%s", addr)
|
||||
|
||||
// Create HTTP server for graceful shutdown
|
||||
srv := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: l,
|
||||
}
|
||||
|
||||
go func() {
|
||||
chk.E(http.ListenAndServe(addr, l))
|
||||
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.E.F("HTTP server error: %v", err)
|
||||
}
|
||||
}()
|
||||
quit = make(chan struct{})
|
||||
|
||||
// Graceful shutdown handler
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
log.I.F("shutting down HTTP server gracefully")
|
||||
|
||||
// Create shutdown context with timeout
|
||||
shutdownCtx, cancelShutdown := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancelShutdown()
|
||||
|
||||
// Shutdown the server gracefully
|
||||
if err := srv.Shutdown(shutdownCtx); err != nil {
|
||||
log.E.F("HTTP server shutdown error: %v", err)
|
||||
} else {
|
||||
log.I.F("HTTP server shutdown completed")
|
||||
}
|
||||
|
||||
once.Do(func() { close(quit) })
|
||||
}()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -54,6 +54,16 @@ func (s *Server) isIPBlacklisted(remote string) bool {
|
||||
// Extract IP from remote address (e.g., "192.168.1.1:12345" -> "192.168.1.1")
|
||||
remoteIP := strings.Split(remote, ":")[0]
|
||||
|
||||
// Check static IP blacklist from config first
|
||||
if len(s.Config.IPBlacklist) > 0 {
|
||||
for _, blocked := range s.Config.IPBlacklist {
|
||||
// Allow simple prefix matching for subnets (e.g., "192.168" matches 192.168.0.0/16)
|
||||
if blocked != "" && strings.HasPrefix(remoteIP, blocked) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if managed ACL is available and active
|
||||
if s.Config.ACLMode == "managed" {
|
||||
for _, aclInstance := range acl.Registry.ACL {
|
||||
|
||||
Reference in New Issue
Block a user