Phase2
This commit is contained in:
@@ -6,28 +6,43 @@ import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/hexahost/gamecloud/node-agent/internal/config"
|
||||
dockerpkg "github.com/hexahost/gamecloud/node-agent/internal/docker"
|
||||
"github.com/hexahost/gamecloud/node-agent/internal/health"
|
||||
"github.com/hexahost/gamecloud/node-agent/internal/runtime"
|
||||
"github.com/hexahost/gamecloud/node-agent/internal/ws"
|
||||
)
|
||||
|
||||
const Version = "0.1.0-phase0"
|
||||
const Version = "0.2.0-phase2"
|
||||
|
||||
// Agent coordinates the node agent lifecycle until shutdown.
|
||||
type Agent struct {
|
||||
cfg *config.Config
|
||||
log *slog.Logger
|
||||
health *health.Server
|
||||
docker *dockerpkg.Client
|
||||
ws *ws.Client
|
||||
}
|
||||
|
||||
// New creates an agent instance from configuration.
|
||||
func New(cfg *config.Config, log *slog.Logger) *Agent {
|
||||
func New(cfg *config.Config, log *slog.Logger) (*Agent, error) {
|
||||
dockerClient, err := dockerpkg.New(cfg.DockerSocket)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wsClient := ws.NewClient(cfg, log, nil, Version)
|
||||
runtimeMgr := runtime.NewManager(dockerClient, wsClient, log)
|
||||
wsClient.SetRuntime(runtimeMgr)
|
||||
|
||||
return &Agent{
|
||||
cfg: cfg,
|
||||
log: log,
|
||||
health: health.NewServer(cfg.HealthListenAddr, Version),
|
||||
}
|
||||
docker: dockerClient,
|
||||
ws: wsClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Run starts the agent loop and blocks until context cancellation or signal.
|
||||
@@ -39,7 +54,7 @@ func (a *Agent) Run(ctx context.Context) error {
|
||||
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||
defer signal.Stop(sigCh)
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
errCh := make(chan error, 2)
|
||||
go func() {
|
||||
a.log.Info("health server listening", "addr", a.cfg.HealthListenAddr)
|
||||
if err := a.health.ListenAndServe(); err != nil {
|
||||
@@ -47,6 +62,10 @@ func (a *Agent) Run(ctx context.Context) error {
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
errCh <- a.ws.Run(ctx)
|
||||
}()
|
||||
|
||||
a.health.SetReady(true)
|
||||
a.log.Info("agent started",
|
||||
"node_id", a.cfg.NodeID,
|
||||
@@ -54,34 +73,33 @@ func (a *Agent) Run(ctx context.Context) error {
|
||||
"version", Version,
|
||||
)
|
||||
|
||||
ticker := time.NewTicker(a.cfg.HeartbeatInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return a.shutdown(ctx.Err())
|
||||
return a.shutdown(nil)
|
||||
case sig := <-sigCh:
|
||||
a.log.Info("shutdown signal received", "signal", sig.String())
|
||||
return a.shutdown(nil)
|
||||
cancel()
|
||||
case err := <-errCh:
|
||||
return err
|
||||
case <-ticker.C:
|
||||
a.log.Debug("heartbeat tick",
|
||||
"node_id", a.cfg.NodeID,
|
||||
"interval", a.cfg.HeartbeatInterval.String(),
|
||||
)
|
||||
if ctx.Err() != nil {
|
||||
return a.shutdown(nil)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Agent) shutdown(reason error) error {
|
||||
a.health.SetReady(false)
|
||||
a.log.Info("agent shutting down", "grace", a.cfg.ShutdownGracePeriod.String())
|
||||
a.log.Info("agent shutting down")
|
||||
|
||||
timer := time.NewTimer(a.cfg.ShutdownGracePeriod)
|
||||
defer timer.Stop()
|
||||
<-timer.C
|
||||
if a.docker != nil {
|
||||
if err := a.docker.Close(); err != nil {
|
||||
a.log.Warn("docker client close failed", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
if reason != nil && reason != context.Canceled {
|
||||
a.log.Warn("shutdown with error", "error", reason)
|
||||
|
||||
Reference in New Issue
Block a user