alert: wire engine into ws hello + MarkJobFinished + offline sweep
- ws.HandlerDeps gains an AlertEngine *alert.Engine field; populated from http.Deps.AlertEngine (nil until G1 constructs the engine) - runAgentLoop calls NotifyHostOnline after MarkHostHello succeeds - dispatchAgentMessage MsgJobFinished case calls NotifyJobFinished, looking up the job Kind via Store.GetJob before notifying - store.MarkHostsOfflineStaleReturnIDs added: SELECT+UPDATE in one transaction, returns the IDs that flipped to offline - offline sweeper in cmd/server/main.go switched to the new variant; TODO(G1) comment marks where NotifyHostOffline calls will land
This commit is contained in:
@@ -110,6 +110,55 @@ func (s *Store) MarkHostsOfflineStale(ctx context.Context, cutoff time.Time) (in
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// MarkHostsOfflineStaleReturnIDs flips any host that hasn't been seen
|
||||
// since before `cutoff` from 'online' to 'offline' and returns the IDs
|
||||
// of every host that was flipped. Uses a single transaction.
|
||||
func (s *Store) MarkHostsOfflineStaleReturnIDs(ctx context.Context, cutoff time.Time) ([]string, error) {
|
||||
tx, err := s.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("store: begin tx: %w", err)
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
cutoffStr := cutoff.UTC().Format(time.RFC3339Nano)
|
||||
rows, err := tx.QueryContext(ctx,
|
||||
`SELECT id FROM hosts
|
||||
WHERE status = 'online'
|
||||
AND (last_seen_at IS NULL OR last_seen_at < ?)`,
|
||||
cutoffStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("store: select stale hosts: %w", err)
|
||||
}
|
||||
var ids []string
|
||||
for rows.Next() {
|
||||
var id string
|
||||
if err := rows.Scan(&id); err != nil {
|
||||
_ = rows.Close()
|
||||
return nil, fmt.Errorf("store: scan stale host id: %w", err)
|
||||
}
|
||||
ids = append(ids, id)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("store: iterate stale hosts: %w", err)
|
||||
}
|
||||
_ = rows.Close()
|
||||
|
||||
if len(ids) > 0 {
|
||||
if _, err := tx.ExecContext(ctx,
|
||||
`UPDATE hosts SET status = 'offline'
|
||||
WHERE status = 'online'
|
||||
AND (last_seen_at IS NULL OR last_seen_at < ?)`,
|
||||
cutoffStr); err != nil {
|
||||
return nil, fmt.Errorf("store: mark offline: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, fmt.Errorf("store: commit: %w", err)
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// ListHosts returns every host. Phase 1 callers fit a small fleet in
|
||||
// memory; pagination lands when it matters.
|
||||
func (s *Store) ListHosts(ctx context.Context) ([]Host, error) {
|
||||
|
||||
Reference in New Issue
Block a user