Trenne Lifecycle und Server-Connectivity im Agenten
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
parent
896eade0fb
commit
9ee24fe4ae
2 changed files with 79 additions and 23 deletions
|
|
@ -14,20 +14,27 @@ import (
|
|||
|
||||
type Status string
|
||||
|
||||
type Connectivity string
|
||||
|
||||
const (
|
||||
StatusStarting Status = "starting"
|
||||
StatusRunning Status = "running"
|
||||
StatusStopped Status = "stopped"
|
||||
|
||||
ConnectivityUnknown Connectivity = "unknown"
|
||||
ConnectivityOnline Connectivity = "online"
|
||||
ConnectivityDegraded Connectivity = "degraded"
|
||||
)
|
||||
|
||||
type HealthSnapshot struct {
|
||||
Status Status
|
||||
ScreenID string
|
||||
ServerBaseURL string
|
||||
MQTTBroker string
|
||||
HeartbeatEvery int
|
||||
StartedAt time.Time
|
||||
LastHeartbeatAt time.Time
|
||||
Status Status
|
||||
ServerConnectivity Connectivity
|
||||
ScreenID string
|
||||
ServerBaseURL string
|
||||
MQTTBroker string
|
||||
HeartbeatEvery int
|
||||
StartedAt time.Time
|
||||
LastHeartbeatAt time.Time
|
||||
}
|
||||
|
||||
type App struct {
|
||||
|
|
@ -36,10 +43,11 @@ type App struct {
|
|||
now func() time.Time
|
||||
reporter statusSender
|
||||
|
||||
mu sync.RWMutex
|
||||
status Status
|
||||
startedAt time.Time
|
||||
lastHeartbeatAt time.Time
|
||||
mu sync.RWMutex
|
||||
status Status
|
||||
serverConnectivity Connectivity
|
||||
startedAt time.Time
|
||||
lastHeartbeatAt time.Time
|
||||
}
|
||||
|
||||
type statusSender interface {
|
||||
|
|
@ -67,11 +75,12 @@ func newApp(cfg config.Config, logger *log.Logger, now func() time.Time, reporte
|
|||
}
|
||||
|
||||
return &App{
|
||||
Config: cfg,
|
||||
logger: logger,
|
||||
now: now,
|
||||
reporter: reporter,
|
||||
status: StatusStarting,
|
||||
Config: cfg,
|
||||
logger: logger,
|
||||
now: now,
|
||||
reporter: reporter,
|
||||
status: StatusStarting,
|
||||
serverConnectivity: ConnectivityUnknown,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -80,13 +89,14 @@ func (a *App) Snapshot() HealthSnapshot {
|
|||
defer a.mu.RUnlock()
|
||||
|
||||
return HealthSnapshot{
|
||||
Status: a.status,
|
||||
ScreenID: a.Config.ScreenID,
|
||||
ServerBaseURL: a.Config.ServerBaseURL,
|
||||
MQTTBroker: a.Config.MQTTBroker,
|
||||
HeartbeatEvery: a.Config.HeartbeatEvery,
|
||||
StartedAt: a.startedAt,
|
||||
LastHeartbeatAt: a.lastHeartbeatAt,
|
||||
Status: a.status,
|
||||
ServerConnectivity: a.serverConnectivity,
|
||||
ScreenID: a.Config.ScreenID,
|
||||
ServerBaseURL: a.Config.ServerBaseURL,
|
||||
MQTTBroker: a.Config.MQTTBroker,
|
||||
HeartbeatEvery: a.Config.HeartbeatEvery,
|
||||
StartedAt: a.startedAt,
|
||||
LastHeartbeatAt: a.lastHeartbeatAt,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -170,9 +180,15 @@ func (a *App) reportStatus(ctx context.Context) {
|
|||
LastHeartbeatAt: snapshot.LastHeartbeatAt,
|
||||
})
|
||||
if err != nil {
|
||||
a.mu.Lock()
|
||||
a.serverConnectivity = ConnectivityDegraded
|
||||
a.mu.Unlock()
|
||||
a.logger.Printf("event=status_report_failed screen_id=%s error=%v", a.Config.ScreenID, err)
|
||||
return
|
||||
}
|
||||
|
||||
a.mu.Lock()
|
||||
a.serverConnectivity = ConnectivityOnline
|
||||
a.mu.Unlock()
|
||||
a.logger.Printf("event=status_report_sent screen_id=%s", a.Config.ScreenID)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,6 +119,10 @@ func TestAppSnapshotIncludesConfiguredTargets(t *testing.T) {
|
|||
if got, want := snapshot.HeartbeatEvery, 15; got != want {
|
||||
t.Fatalf("HeartbeatEvery = %d, want %d", got, want)
|
||||
}
|
||||
|
||||
if got, want := snapshot.ServerConnectivity, ConnectivityUnknown; got != want {
|
||||
t.Fatalf("ServerConnectivity = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppRunWithCanceledContextDoesNotLogConfiguredOrHeartbeat(t *testing.T) {
|
||||
|
|
@ -195,4 +199,40 @@ func TestAppRunReportsStatusWithoutStoppingOnReporterError(t *testing.T) {
|
|||
if !strings.Contains(logs, "event=status_report_failed") {
|
||||
t.Fatalf("logs missing status_report_failed event: %s", logs)
|
||||
}
|
||||
|
||||
if got, want := application.Snapshot().ServerConnectivity, ConnectivityDegraded; got != want {
|
||||
t.Fatalf("ServerConnectivity = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppRunMarksServerConnectivityOnlineAfterSuccessfulReport(t *testing.T) {
|
||||
application := newApp(config.Config{
|
||||
ScreenID: "screen-online",
|
||||
ServerBaseURL: "http://127.0.0.1:8080",
|
||||
MQTTBroker: "tcp://127.0.0.1:1883",
|
||||
HeartbeatEvery: 1,
|
||||
StatusReportEvery: 1,
|
||||
}, log.New(&bytes.Buffer{}, "", 0), time.Now, &recordingReporter{})
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
errCh <- application.Run(ctx)
|
||||
}()
|
||||
|
||||
deadline := time.Now().Add(2 * time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
if application.Snapshot().ServerConnectivity == ConnectivityOnline {
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
if got, want := application.Snapshot().ServerConnectivity, ConnectivityOnline; got != want {
|
||||
cancel()
|
||||
t.Fatalf("ServerConnectivity = %q, want %q", got, want)
|
||||
}
|
||||
|
||||
cancel()
|
||||
<-errCh
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue