mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-06-04 22:59:26 +00:00
3aa83d4480
* chore(security,refactor): extract sanitization and improve code quality
- [x] Extract sanitization functions to dedicated sanitization.go module
- [x] Add comprehensive golangci-lint v2 configuration with security rules
- [x] Replace interface{} with any type throughout codebase
- [x] Add admin API authentication security warning
- [x] Extract WebSocket and stats streaming constants
- [x] Add best-effort error handling comments for resource cleanup
- [x] Expand sensitive field patterns for improved PII redaction
- [x] Simplify safety checks and remove redundant nil validations
- [x] Improve test coverage for password field redaction patterns
* refactor: replace interface{} with any type alias
- [x] Replace all `map[string]interface{}` with `map[string]any`
- [x] Replace all `interface{}` with `any` in function signatures and type definitions
- [x] Update sync.Pool New function returns from `interface{}` to `any`
- [x] Add package documentation comments to 8 package files
- [x] Update type assertions and casts to work with `any` type
195 lines
4.5 KiB
Go
195 lines
4.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"time"
|
|
|
|
libpack_logging "github.com/lukaszraczylo/graphql-monitoring-proxy/logging"
|
|
)
|
|
|
|
// ShutdownManager manages graceful shutdown for all components
|
|
type ShutdownManager struct {
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
components []ShutdownComponent
|
|
wg sync.WaitGroup
|
|
shutdownOnce sync.Once
|
|
mu sync.Mutex
|
|
}
|
|
|
|
// ShutdownComponent represents a component that needs graceful shutdown
|
|
type ShutdownComponent struct {
|
|
Shutdown func(context.Context) error
|
|
Name string
|
|
}
|
|
|
|
// NewShutdownManager creates a new shutdown manager
|
|
func NewShutdownManager(ctx context.Context) *ShutdownManager {
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
return &ShutdownManager{
|
|
ctx: ctx,
|
|
cancel: cancel,
|
|
}
|
|
}
|
|
|
|
// RegisterComponent registers a component for graceful shutdown
|
|
func (sm *ShutdownManager) RegisterComponent(name string, shutdown func(context.Context) error) {
|
|
sm.mu.Lock()
|
|
defer sm.mu.Unlock()
|
|
sm.components = append(sm.components, ShutdownComponent{
|
|
Name: name,
|
|
Shutdown: shutdown,
|
|
})
|
|
}
|
|
|
|
// RunGoroutine starts a goroutine that respects the shutdown context
|
|
func (sm *ShutdownManager) RunGoroutine(name string, fn func(context.Context)) {
|
|
sm.wg.Add(1)
|
|
go func() {
|
|
defer sm.wg.Done()
|
|
cfgMutex.RLock()
|
|
logger := cfg.Logger
|
|
cfgMutex.RUnlock()
|
|
if logger != nil {
|
|
logger.Debug(&libpack_logging.LogMessage{
|
|
Message: "Starting managed goroutine",
|
|
Pairs: map[string]any{"name": name},
|
|
})
|
|
}
|
|
fn(sm.ctx)
|
|
cfgMutex.RLock()
|
|
logger = cfg.Logger
|
|
cfgMutex.RUnlock()
|
|
if logger != nil {
|
|
logger.Debug(&libpack_logging.LogMessage{
|
|
Message: "Managed goroutine finished",
|
|
Pairs: map[string]any{"name": name},
|
|
})
|
|
}
|
|
}()
|
|
}
|
|
|
|
// Shutdown initiates graceful shutdown of all components
|
|
func (sm *ShutdownManager) Shutdown(timeout time.Duration) error {
|
|
var err error
|
|
sm.shutdownOnce.Do(func() {
|
|
err = sm.doShutdown(timeout)
|
|
})
|
|
return err
|
|
}
|
|
|
|
// doShutdown performs the actual shutdown logic
|
|
func (sm *ShutdownManager) doShutdown(timeout time.Duration) error {
|
|
cfgMutex.RLock()
|
|
logger := cfg.Logger
|
|
cfgMutex.RUnlock()
|
|
if logger != nil {
|
|
logger.Info(&libpack_logging.LogMessage{
|
|
Message: "Initiating graceful shutdown",
|
|
})
|
|
}
|
|
|
|
// Cancel the context to signal all goroutines to stop
|
|
sm.cancel()
|
|
|
|
// Create a timeout context for component shutdown
|
|
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), timeout)
|
|
defer shutdownCancel()
|
|
|
|
// Shutdown all registered components
|
|
sm.mu.Lock()
|
|
components := make([]ShutdownComponent, len(sm.components))
|
|
copy(components, sm.components)
|
|
sm.mu.Unlock()
|
|
|
|
var shutdownWg sync.WaitGroup
|
|
for _, comp := range components {
|
|
shutdownWg.Add(1)
|
|
go func(c ShutdownComponent) {
|
|
defer shutdownWg.Done()
|
|
cfgMutex.RLock()
|
|
logger := cfg.Logger
|
|
cfgMutex.RUnlock()
|
|
if logger != nil {
|
|
logger.Info(&libpack_logging.LogMessage{
|
|
Message: "Shutting down component",
|
|
Pairs: map[string]any{"component": c.Name},
|
|
})
|
|
}
|
|
if err := c.Shutdown(shutdownCtx); err != nil {
|
|
cfgMutex.RLock()
|
|
logger := cfg.Logger
|
|
cfgMutex.RUnlock()
|
|
if logger != nil {
|
|
logger.Error(&libpack_logging.LogMessage{
|
|
Message: "Error shutting down component",
|
|
Pairs: map[string]any{
|
|
"component": c.Name,
|
|
"error": err.Error(),
|
|
},
|
|
})
|
|
}
|
|
}
|
|
}(comp)
|
|
}
|
|
|
|
// Wait for all components to shutdown
|
|
componentsDone := make(chan struct{})
|
|
go func() {
|
|
shutdownWg.Wait()
|
|
close(componentsDone)
|
|
}()
|
|
|
|
// Wait for goroutines with timeout
|
|
goroutinesDone := make(chan struct{})
|
|
go func() {
|
|
sm.wg.Wait()
|
|
close(goroutinesDone)
|
|
}()
|
|
|
|
select {
|
|
case <-componentsDone:
|
|
cfgMutex.RLock()
|
|
logger := cfg.Logger
|
|
cfgMutex.RUnlock()
|
|
if logger != nil {
|
|
logger.Info(&libpack_logging.LogMessage{
|
|
Message: "All components shut down successfully",
|
|
})
|
|
}
|
|
case <-shutdownCtx.Done():
|
|
cfgMutex.RLock()
|
|
logger := cfg.Logger
|
|
cfgMutex.RUnlock()
|
|
if logger != nil {
|
|
logger.Warning(&libpack_logging.LogMessage{
|
|
Message: "Component shutdown timed out",
|
|
})
|
|
}
|
|
}
|
|
|
|
select {
|
|
case <-goroutinesDone:
|
|
cfgMutex.RLock()
|
|
logger := cfg.Logger
|
|
cfgMutex.RUnlock()
|
|
if logger != nil {
|
|
logger.Info(&libpack_logging.LogMessage{
|
|
Message: "All goroutines finished",
|
|
})
|
|
}
|
|
case <-time.After(timeout):
|
|
cfgMutex.RLock()
|
|
logger := cfg.Logger
|
|
cfgMutex.RUnlock()
|
|
if logger != nil {
|
|
logger.Warning(&libpack_logging.LogMessage{
|
|
Message: "Some goroutines didn't finish within timeout",
|
|
})
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|