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,14 +14,21 @@ import (
|
||||||
|
|
||||||
type Status string
|
type Status string
|
||||||
|
|
||||||
|
type Connectivity string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
StatusStarting Status = "starting"
|
StatusStarting Status = "starting"
|
||||||
StatusRunning Status = "running"
|
StatusRunning Status = "running"
|
||||||
StatusStopped Status = "stopped"
|
StatusStopped Status = "stopped"
|
||||||
|
|
||||||
|
ConnectivityUnknown Connectivity = "unknown"
|
||||||
|
ConnectivityOnline Connectivity = "online"
|
||||||
|
ConnectivityDegraded Connectivity = "degraded"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HealthSnapshot struct {
|
type HealthSnapshot struct {
|
||||||
Status Status
|
Status Status
|
||||||
|
ServerConnectivity Connectivity
|
||||||
ScreenID string
|
ScreenID string
|
||||||
ServerBaseURL string
|
ServerBaseURL string
|
||||||
MQTTBroker string
|
MQTTBroker string
|
||||||
|
|
@ -38,6 +45,7 @@ type App struct {
|
||||||
|
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
status Status
|
status Status
|
||||||
|
serverConnectivity Connectivity
|
||||||
startedAt time.Time
|
startedAt time.Time
|
||||||
lastHeartbeatAt time.Time
|
lastHeartbeatAt time.Time
|
||||||
}
|
}
|
||||||
|
|
@ -72,6 +80,7 @@ func newApp(cfg config.Config, logger *log.Logger, now func() time.Time, reporte
|
||||||
now: now,
|
now: now,
|
||||||
reporter: reporter,
|
reporter: reporter,
|
||||||
status: StatusStarting,
|
status: StatusStarting,
|
||||||
|
serverConnectivity: ConnectivityUnknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,6 +90,7 @@ func (a *App) Snapshot() HealthSnapshot {
|
||||||
|
|
||||||
return HealthSnapshot{
|
return HealthSnapshot{
|
||||||
Status: a.status,
|
Status: a.status,
|
||||||
|
ServerConnectivity: a.serverConnectivity,
|
||||||
ScreenID: a.Config.ScreenID,
|
ScreenID: a.Config.ScreenID,
|
||||||
ServerBaseURL: a.Config.ServerBaseURL,
|
ServerBaseURL: a.Config.ServerBaseURL,
|
||||||
MQTTBroker: a.Config.MQTTBroker,
|
MQTTBroker: a.Config.MQTTBroker,
|
||||||
|
|
@ -170,9 +180,15 @@ func (a *App) reportStatus(ctx context.Context) {
|
||||||
LastHeartbeatAt: snapshot.LastHeartbeatAt,
|
LastHeartbeatAt: snapshot.LastHeartbeatAt,
|
||||||
})
|
})
|
||||||
if err != nil {
|
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)
|
a.logger.Printf("event=status_report_failed screen_id=%s error=%v", a.Config.ScreenID, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.mu.Lock()
|
||||||
|
a.serverConnectivity = ConnectivityOnline
|
||||||
|
a.mu.Unlock()
|
||||||
a.logger.Printf("event=status_report_sent screen_id=%s", a.Config.ScreenID)
|
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 {
|
if got, want := snapshot.HeartbeatEvery, 15; got != want {
|
||||||
t.Fatalf("HeartbeatEvery = %d, want %d", 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) {
|
func TestAppRunWithCanceledContextDoesNotLogConfiguredOrHeartbeat(t *testing.T) {
|
||||||
|
|
@ -195,4 +199,40 @@ func TestAppRunReportsStatusWithoutStoppingOnReporterError(t *testing.T) {
|
||||||
if !strings.Contains(logs, "event=status_report_failed") {
|
if !strings.Contains(logs, "event=status_report_failed") {
|
||||||
t.Fatalf("logs missing status_report_failed event: %s", logs)
|
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