feat(v0.4): add lease freshness check and stale cleanup

This commit is contained in:
2026-04-21 17:03:21 -04:00
parent c29985b663
commit bc5410f722
2 changed files with 140 additions and 0 deletions
+42
View File
@@ -2,6 +2,7 @@ package session
import (
"encoding/json"
"errors"
"fmt"
"os"
"os/user"
@@ -113,3 +114,44 @@ func NewLease(startedAt time.Time, agent, mode string) *Lease {
Terminal: currentTerminal(),
}
}
// IsFresh returns true if the lease's last heartbeat is within threshold
// of now. A lease with a zero LastHeartbeatAt is treated as stale.
func IsFresh(l *Lease, now time.Time, threshold time.Duration) bool {
if l == nil || l.LastHeartbeatAt.IsZero() {
return false
}
return now.Sub(l.LastHeartbeatAt) <= threshold
}
// CleanupStaleLease inspects the lease at path:
// - missing file: no-op, returns (nil, nil)
// - corrupt / unparseable: removes the file, returns (nil, nil)
// - stale (heartbeat older than staleAfter): removes the file, returns the parsed lease
// - fresh: no-op, returns (nil, nil)
//
// An I/O error during removal is returned to the caller along with the
// parsed lease (if any), so the caller can log it explicitly.
func CleanupStaleLease(path string, staleAfter time.Duration) (*Lease, error) {
data, err := os.ReadFile(path)
if errors.Is(err, os.ErrNotExist) {
return nil, nil
}
if err != nil {
return nil, err
}
var l Lease
if jsonErr := json.Unmarshal(data, &l); jsonErr != nil {
if rmErr := os.Remove(path); rmErr != nil && !errors.Is(rmErr, os.ErrNotExist) {
return nil, rmErr
}
return nil, nil
}
if IsFresh(&l, time.Now(), staleAfter) {
return nil, nil
}
if rmErr := os.Remove(path); rmErr != nil && !errors.Is(rmErr, os.ErrNotExist) {
return &l, rmErr
}
return &l, nil
}