mirror of
https://github.com/MeshCore-Beacon/beacon-server.git
synced 2026-10-23 06:22:52 +00:00
feat(retention): age out unreferenced observers when enabled (#126)
This commit is contained in:
1 parent
2125df5b61
commit
88bc0dc88a
15 files changed
+530
-19
No files matched your search
@@ -71,6 +71,21 @@ func (mr *MockQuerierMockRecorder) DeleteOldNodes(ctx, lastSeen any) *gomock.Cal
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOldNodes", reflect.TypeOf((*MockQuerier)(nil).DeleteOldNodes), ctx, lastSeen)
|
||||
}
|
||||
|
||||
// DeleteOldObservers mocks base method.
|
||||
func (m *MockQuerier) DeleteOldObservers(ctx context.Context, lastSeen pgtype.Timestamptz) ([]uuid.UUID, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteOldObservers", ctx, lastSeen)
|
||||
ret0, _ := ret[0].([]uuid.UUID)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DeleteOldObservers indicates an expected call of DeleteOldObservers.
|
||||
func (mr *MockQuerierMockRecorder) DeleteOldObservers(ctx, lastSeen any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOldObservers", reflect.TypeOf((*MockQuerier)(nil).DeleteOldObservers), ctx, lastSeen)
|
||||
}
|
||||
|
||||
// DeleteOldPackets mocks base method.
|
||||
func (m *MockQuerier) DeleteOldPackets(ctx context.Context, lastHeardAt pgtype.Timestamptz) error {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@@ -22,6 +22,9 @@ type Querier interface {
|
||||
// dangling in old routes there, but ReconfirmTask already prunes stale/ambiguous routes
|
||||
// periodically and will clean those up on its own schedule.
|
||||
DeleteOldNodes(ctx context.Context, lastSeen pgtype.Timestamptz) error
|
||||
// Opt-in age-out: preserve retained history and manually recorded ownership.
|
||||
// Bound deletions per cleanup tick and skip observers being updated by ingest.
|
||||
DeleteOldObservers(ctx context.Context, lastSeen pgtype.Timestamptz) ([]uuid.UUID, error)
|
||||
// Deletes packets and their observations older than the given cutoff.
|
||||
// packet_observations cascade-delete via FK.
|
||||
DeleteOldPackets(ctx context.Context, lastHeardAt pgtype.Timestamptz) error
|
||||
|
||||
@@ -40,6 +40,46 @@ func (q *Queries) DeleteOldNodes(ctx context.Context, lastSeen pgtype.Timestampt
|
||||
return err
|
||||
}
|
||||
|
||||
const deleteOldObservers = `-- name: DeleteOldObservers :many
|
||||
WITH expired AS (
|
||||
SELECT o.id
|
||||
FROM observers o
|
||||
WHERE o.last_seen < $1
|
||||
AND (o.last_status_at IS NULL OR o.last_status_at < $1)
|
||||
AND NOT EXISTS (SELECT 1 FROM packet_observations po WHERE po.observer_id = o.id)
|
||||
AND NOT EXISTS (SELECT 1 FROM observer_telemetry ot WHERE ot.observer_id = o.id)
|
||||
AND NOT EXISTS (SELECT 1 FROM observer_owners oo WHERE oo.observer_id = o.id)
|
||||
ORDER BY o.last_seen, o.id
|
||||
LIMIT 1000
|
||||
FOR UPDATE OF o SKIP LOCKED
|
||||
)
|
||||
DELETE FROM observers o USING expired e
|
||||
WHERE o.id = e.id
|
||||
RETURNING o.id
|
||||
`
|
||||
|
||||
// Opt-in age-out: preserve retained history and manually recorded ownership.
|
||||
// Bound deletions per cleanup tick and skip observers being updated by ingest.
|
||||
func (q *Queries) DeleteOldObservers(ctx context.Context, lastSeen pgtype.Timestamptz) ([]uuid.UUID, error) {
|
||||
rows, err := q.db.Query(ctx, deleteOldObservers, lastSeen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
items := []uuid.UUID{}
|
||||
for rows.Next() {
|
||||
var id uuid.UUID
|
||||
if err := rows.Scan(&id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, id)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const deleteOldPackets = `-- name: DeleteOldPackets :exec
|
||||
DELETE FROM packets WHERE last_heard_at < $1
|
||||
`
|
||||
|
||||
Reference in new issue
Block a user