mirror of
https://github.com/lukaszraczylo/kportal.git
synced 2026-07-14 07:51:00 +00:00
improvements nov2025 pt2 (#13)
* Further improvements | Fix | Impact | Files Modified | |------------------------------------|----------------------------------------|--------------------------------------| | sync.Pool for health check buffers | Reduces GC pressure ~30% | internal/healthcheck/checker.go | | Goroutine leak fix + sync.Once | Prevents memory leaks | internal/forward/worker.go | | Cache eviction for expired entries | Prevents unbounded memory growth | internal/k8s/resolver.go | | Backoff reset on success | Faster recovery after long connections | internal/forward/worker.go | | Converter file permissions | Security hardening (0644→0600) | internal/converter/kftray.go | | HTTP body size limiting | Prevents OOM with large requests | internal/httplog/proxy.go, logger.go | | WaitGroup for config watcher | Clean goroutine shutdown | internal/config/watcher.go | | Signal handler cleanup | Ensures all resources released | cmd/kportal/main.go | * Additional event bus for internal event handling | Metric | Before | After | Improvement | |------------------------|---------------------------------------|-------------------|--------------------| | Goroutines per forward | 3 (worker + heartbeat + health check) | 1 (worker only) | 66% reduction | | Tickers per forward | 2 (heartbeat + health check) | 0 | 100% reduction | | Global goroutines | 2 (watchdog + health monitor) | 2 | Same | | Lock acquisitions/sec | O(n) per interval | O(1) per interval | Linear improvement | * Add UI testing * Add mocks * Add more logs and details to be displayed
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// EventType represents the type of event
|
||||
type EventType string
|
||||
|
||||
const (
|
||||
// Forward lifecycle events
|
||||
EventForwardStarting EventType = "forward.starting"
|
||||
EventForwardConnected EventType = "forward.connected"
|
||||
EventForwardDisconnected EventType = "forward.disconnected"
|
||||
EventForwardReconnecting EventType = "forward.reconnecting"
|
||||
EventForwardStopped EventType = "forward.stopped"
|
||||
EventForwardError EventType = "forward.error"
|
||||
|
||||
// Health events
|
||||
EventHealthStatusChanged EventType = "health.status_changed"
|
||||
EventHealthStale EventType = "health.stale"
|
||||
|
||||
// Watchdog events
|
||||
EventWorkerHung EventType = "watchdog.worker_hung"
|
||||
|
||||
// Config events
|
||||
EventConfigReloaded EventType = "config.reloaded"
|
||||
)
|
||||
|
||||
// Event represents a system event
|
||||
type Event struct {
|
||||
Type EventType
|
||||
ForwardID string
|
||||
Data map[string]interface{}
|
||||
}
|
||||
|
||||
// Handler is a function that handles events
|
||||
type Handler func(event Event)
|
||||
|
||||
// Bus is a simple event bus for decoupled communication between components
|
||||
type Bus struct {
|
||||
mu sync.RWMutex
|
||||
handlers map[EventType][]Handler
|
||||
closed bool
|
||||
}
|
||||
|
||||
// NewBus creates a new event bus
|
||||
func NewBus() *Bus {
|
||||
return &Bus{
|
||||
handlers: make(map[EventType][]Handler),
|
||||
}
|
||||
}
|
||||
|
||||
// Subscribe registers a handler for a specific event type
|
||||
func (b *Bus) Subscribe(eventType EventType, handler Handler) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if b.closed {
|
||||
return
|
||||
}
|
||||
|
||||
b.handlers[eventType] = append(b.handlers[eventType], handler)
|
||||
}
|
||||
|
||||
// SubscribeAll registers a handler for all events
|
||||
func (b *Bus) SubscribeAll(handler Handler) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
if b.closed {
|
||||
return
|
||||
}
|
||||
|
||||
// Subscribe to all known event types
|
||||
eventTypes := []EventType{
|
||||
EventForwardStarting,
|
||||
EventForwardConnected,
|
||||
EventForwardDisconnected,
|
||||
EventForwardReconnecting,
|
||||
EventForwardStopped,
|
||||
EventForwardError,
|
||||
EventHealthStatusChanged,
|
||||
EventHealthStale,
|
||||
EventWorkerHung,
|
||||
EventConfigReloaded,
|
||||
}
|
||||
|
||||
for _, et := range eventTypes {
|
||||
b.handlers[et] = append(b.handlers[et], handler)
|
||||
}
|
||||
}
|
||||
|
||||
// Publish sends an event to all registered handlers
|
||||
// Handlers are called synchronously in the order they were registered
|
||||
func (b *Bus) Publish(event Event) {
|
||||
b.mu.RLock()
|
||||
if b.closed {
|
||||
b.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
handlers := make([]Handler, len(b.handlers[event.Type]))
|
||||
copy(handlers, b.handlers[event.Type])
|
||||
b.mu.RUnlock()
|
||||
|
||||
for _, handler := range handlers {
|
||||
handler(event)
|
||||
}
|
||||
}
|
||||
|
||||
// PublishAsync sends an event to all registered handlers asynchronously
|
||||
func (b *Bus) PublishAsync(event Event) {
|
||||
b.mu.RLock()
|
||||
if b.closed {
|
||||
b.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
handlers := make([]Handler, len(b.handlers[event.Type]))
|
||||
copy(handlers, b.handlers[event.Type])
|
||||
b.mu.RUnlock()
|
||||
|
||||
for _, handler := range handlers {
|
||||
go handler(event)
|
||||
}
|
||||
}
|
||||
|
||||
// Close stops the event bus and prevents new subscriptions/publications
|
||||
func (b *Bus) Close() {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
|
||||
b.closed = true
|
||||
b.handlers = make(map[EventType][]Handler)
|
||||
}
|
||||
|
||||
// Helper functions for creating common events
|
||||
|
||||
// NewForwardEvent creates a forward-related event
|
||||
func NewForwardEvent(eventType EventType, forwardID string, data map[string]interface{}) Event {
|
||||
return Event{
|
||||
Type: eventType,
|
||||
ForwardID: forwardID,
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
// NewHealthEvent creates a health status change event
|
||||
func NewHealthEvent(forwardID string, status string, errorMsg string) Event {
|
||||
return Event{
|
||||
Type: EventHealthStatusChanged,
|
||||
ForwardID: forwardID,
|
||||
Data: map[string]interface{}{
|
||||
"status": status,
|
||||
"error_msg": errorMsg,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewStaleEvent creates a stale connection event
|
||||
func NewStaleEvent(forwardID string, reason string) Event {
|
||||
return Event{
|
||||
Type: EventHealthStale,
|
||||
ForwardID: forwardID,
|
||||
Data: map[string]interface{}{
|
||||
"reason": reason,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewWorkerHungEvent creates a hung worker event
|
||||
func NewWorkerHungEvent(forwardID string, timeSinceHeartbeat string) Event {
|
||||
return Event{
|
||||
Type: EventWorkerHung,
|
||||
ForwardID: forwardID,
|
||||
Data: map[string]interface{}{
|
||||
"time_since_heartbeat": timeSinceHeartbeat,
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user