Unified Storage: Adds pruner for kv eventstore (#110785)

* Adds pruner for eventstore - default 24 hours. Adds tests.

* update comment

* remove delay on startup. formatting

* updates log message type and removes useless comment

* caller handles goroutine for runCleanupOldEvents()

* simplify timestamp extraction

* adds config for event pruning interval

* uses start and end key to get all expired events

* remove sort when listing keys in event pruner - order doesnt matter

* use snowflake constants

* log when we delete 0 rows

* pass time.Time to cleanup old events func
This commit is contained in:
owensmallwood
2025-09-12 14:40:16 -06:00
committed by GitHub
parent c5ed2780ab
commit 7ce971cba1
3 changed files with 241 additions and 24 deletions
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -468,3 +469,135 @@ func TestEventStore_Save_InvalidJSON(t *testing.T) {
err := store.Save(ctx, event)
assert.NoError(t, err)
}
func TestEventStore_CleanupOldEvents(t *testing.T) {
ctx := context.Background()
store := setupTestEventStore(t)
now := time.Now()
oldRV := snowflakeFromTime(now.Add(-48 * time.Hour)) // 48 hours ago
recentRV := snowflakeFromTime(now.Add(-1 * time.Hour)) // 1 hour ago
oldEvent := Event{
Namespace: "default",
Group: "apps",
Resource: "resource",
Name: "old-resource",
ResourceVersion: oldRV,
Action: DataActionCreated,
Folder: "test-folder",
PreviousRV: 999,
}
recentEvent := Event{
Namespace: "default",
Group: "apps",
Resource: "resource",
Name: "recent-resource",
ResourceVersion: recentRV,
Action: DataActionCreated,
Folder: "test-folder",
PreviousRV: 999,
}
// Save both events
err := store.Save(ctx, oldEvent)
require.NoError(t, err)
err = store.Save(ctx, recentEvent)
require.NoError(t, err)
// Verify both events exist
_, err = store.Get(ctx, EventKey{
Namespace: oldEvent.Namespace,
Group: oldEvent.Group,
Resource: oldEvent.Resource,
Name: oldEvent.Name,
ResourceVersion: oldEvent.ResourceVersion,
Action: oldEvent.Action,
})
require.NoError(t, err)
_, err = store.Get(ctx, EventKey{
Namespace: recentEvent.Namespace,
Group: recentEvent.Group,
Resource: recentEvent.Resource,
Name: recentEvent.Name,
ResourceVersion: recentEvent.ResourceVersion,
Action: recentEvent.Action,
})
require.NoError(t, err)
// Clean up events older than 24 hours
deletedCount, err := store.CleanupOldEvents(ctx, time.Now().Add(-24*time.Hour))
require.NoError(t, err)
assert.Equal(t, 1, deletedCount, "Should have deleted 1 old event")
// Verify old event was deleted
_, err = store.Get(ctx, EventKey{
Namespace: oldEvent.Namespace,
Group: oldEvent.Group,
Resource: oldEvent.Resource,
Name: oldEvent.Name,
ResourceVersion: oldEvent.ResourceVersion,
Action: oldEvent.Action,
})
assert.Error(t, err, "Old event should have been deleted")
// Verify recent event still exists
_, err = store.Get(ctx, EventKey{
Namespace: recentEvent.Namespace,
Group: recentEvent.Group,
Resource: recentEvent.Resource,
Name: recentEvent.Name,
ResourceVersion: recentEvent.ResourceVersion,
Action: recentEvent.Action,
})
require.NoError(t, err, "Recent event should still exist")
}
func TestEventStore_CleanupOldEvents_NoOldEvents(t *testing.T) {
ctx := context.Background()
store := setupTestEventStore(t)
// Create an event 1 hour old
rv := snowflakeFromTime(time.Now().Add(-1 * time.Hour))
event := Event{
Namespace: "default",
Group: "apps",
Resource: "resource",
Name: "recent-resource",
ResourceVersion: rv,
Action: DataActionCreated,
Folder: "test-folder",
PreviousRV: 999,
}
err := store.Save(ctx, event)
require.NoError(t, err)
// Clean up events older than 24 hours
deletedCount, err := store.CleanupOldEvents(ctx, time.Now().Add(-24*time.Hour))
require.NoError(t, err)
assert.Equal(t, 0, deletedCount, "Should not have deleted any events")
// Verify event still exists
_, err = store.Get(ctx, EventKey{
Namespace: event.Namespace,
Group: event.Group,
Resource: event.Resource,
Name: event.Name,
ResourceVersion: event.ResourceVersion,
Action: event.Action,
})
require.NoError(t, err, "Recent event should still exist")
}
func TestEventStore_CleanupOldEvents_EmptyStore(t *testing.T) {
ctx := context.Background()
store := setupTestEventStore(t)
// Clean up events from empty store
deletedCount, err := store.CleanupOldEvents(ctx, time.Now().Add(-24*time.Hour))
require.NoError(t, err)
assert.Equal(t, 0, deletedCount, "Should not have deleted any events from empty store")
}