feat(v0.4): add lease freshness check and stale cleanup
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user