molecule-core/platform/internal/registry/liveness.go
Hongming Wang 24fec62d7f initial commit — Molecule AI platform
Forked clean from public hackathon repo (Starfire-AgentTeam, BSL 1.1)
with full rebrand to Molecule AI under github.com/Molecule-AI/molecule-monorepo.

Brand: Starfire → Molecule AI.
Slug: starfire / agent-molecule → molecule.
Env vars: STARFIRE_* → MOLECULE_*.
Go module: github.com/agent-molecule/platform → github.com/Molecule-AI/molecule-monorepo/platform.
Python packages: starfire_plugin → molecule_plugin, starfire_agent → molecule_agent.
DB: agentmolecule → molecule.

History truncated; see public repo for prior commits and contributor
attribution. Verified green: go test -race ./... (platform), pytest
(workspace-template 1129 + sdk 132), vitest (canvas 352), build (mcp).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 11:55:37 -07:00

60 lines
1.5 KiB
Go

package registry
import (
"context"
"log"
"strings"
"github.com/Molecule-AI/molecule-monorepo/platform/internal/db"
)
// OfflineHandler is called when a workspace's liveness key expires.
type OfflineHandler func(ctx context.Context, workspaceID string)
// StartLivenessMonitor subscribes to Redis keyspace expiry events.
// When a workspace's liveness key (ws:{id}) expires, it marks the workspace offline
// and calls the onOffline handler.
func StartLivenessMonitor(ctx context.Context, onOffline OfflineHandler) {
sub := db.RDB.PSubscribe(ctx, "__keyevent@0__:expired")
log.Println("Liveness monitor started — listening for Redis key expirations")
ch := sub.Channel()
for {
select {
case <-ctx.Done():
sub.Close()
return
case msg := <-ch:
if msg == nil {
continue
}
key := msg.Payload
if !strings.HasPrefix(key, "ws:") {
continue
}
parts := strings.SplitN(key, ":", 3)
if len(parts) != 2 {
continue
}
workspaceID := parts[1]
log.Printf("Liveness: workspace %s TTL expired", workspaceID)
// Mark offline in Postgres — skip paused workspaces (they have no container)
_, err := db.DB.ExecContext(ctx, `
UPDATE workspaces SET status = 'offline', updated_at = now()
WHERE id = $1 AND status NOT IN ('removed', 'paused')
`, workspaceID)
if err != nil {
log.Printf("Liveness: failed to mark %s offline: %v", workspaceID, err)
continue
}
if onOffline != nil {
onOffline(ctx, workspaceID)
}
}
}
}