Files
x/service/status.go
T
ginuerzh 1c07cf6394 fix(service): default nil logger, fix Events() allocation, collect Close errors
- Default nil logger to Nop() in NewService to prevent panics
- Fix Events() returning 20-element slice padded with zero values
- Collect and join all errors in Close() instead of discarding
- Remove unnecessary variable shadow in execCmds
- Add doc comments to all 22 exported symbols
- Add 34 tests covering status, serve loop, close, and edge cases
2026-05-25 23:47:47 +08:00

92 lines
2.2 KiB
Go

package service
import (
"sync"
"time"
"github.com/go-gost/core/observer/stats"
)
// MaxEventSize is the maximum number of events retained in a Status event log.
// When the log is full, the oldest event is discarded.
const MaxEventSize = 20
// State represents the operational state of a service.
type State string
const (
// StateRunning indicates the service has been created but is not yet accepting.
StateRunning State = "running"
// StateReady indicates the service is actively accepting connections.
StateReady State = "ready"
// StateFailed indicates the service accept loop encountered a temporary error.
StateFailed State = "failed"
// StateClosed indicates the service has been shut down.
StateClosed State = "closed"
)
// Event records a state change or notable occurrence in a service's lifetime.
type Event struct {
Time time.Time
Message string
}
// Status tracks the runtime state, event log, and traffic statistics of a service.
type Status struct {
createTime time.Time
state State
events []Event
stats stats.Stats
mu sync.RWMutex
}
// CreateTime returns the time at which the service was created.
func (p *Status) CreateTime() time.Time {
return p.createTime
}
// State returns the current service state.
func (p *Status) State() State {
p.mu.RLock()
defer p.mu.RUnlock()
return p.state
}
func (p *Status) setState(state State) {
p.mu.Lock()
defer p.mu.Unlock()
p.state = state
}
// Events returns a snapshot of the recent event log. The returned slice is safe
// to modify without affecting the internal state.
func (p *Status) Events() []Event {
p.mu.RLock()
defer p.mu.RUnlock()
events := make([]Event, len(p.events))
copy(events, p.events)
return events
}
func (p *Status) addEvent(event Event) {
p.mu.Lock()
defer p.mu.Unlock()
if len(p.events) == MaxEventSize {
events := make([]Event, MaxEventSize-1, MaxEventSize)
copy(events, p.events[1:])
p.events = events
}
p.events = append(p.events, event)
}
// Stats returns the traffic statistics for the service. It safely handles nil
// receivers by returning nil.
func (p *Status) Stats() stats.Stats {
if p == nil {
return nil
}
return p.stats
}