Skip to content

Commit a74273f

Browse files
authored
chore(coderd/database/dbpurge): replace usage of time.* with quartz (coder#14480)
Related to coder#10576 This PR introduces quartz to coderd/database/dbpurge and updates the following unit tests to make use of Quartz's functionality: - TestPurge - TestDeleteOldWorkspaceAgentLogs Additionally, updates DeleteOldWorkspaceAgentLogs to replace the hard-coded interval with a parameter passed into the query. This aids in testing and brings us a step towards allowing operators to configure the cutoff interval for workspace agent logs.
1 parent c90be9b commit a74273f

File tree

11 files changed

+120
-86
lines changed

11 files changed

+120
-86
lines changed

cli/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -985,7 +985,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
985985
defer shutdownConns()
986986

987987
// Ensures that old database entries are cleaned up over time!
988-
purger := dbpurge.New(ctx, logger.Named("dbpurge"), options.Database)
988+
purger := dbpurge.New(ctx, logger.Named("dbpurge"), options.Database, quartz.NewReal())
989989
defer purger.Close()
990990

991991
// Updates workspace usage

coderd/database/dbauthz/dbauthz.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,11 +1144,11 @@ func (q *querier) DeleteOldProvisionerDaemons(ctx context.Context) error {
11441144
return q.db.DeleteOldProvisionerDaemons(ctx)
11451145
}
11461146

1147-
func (q *querier) DeleteOldWorkspaceAgentLogs(ctx context.Context) error {
1147+
func (q *querier) DeleteOldWorkspaceAgentLogs(ctx context.Context, threshold time.Time) error {
11481148
if err := q.authorizeContext(ctx, policy.ActionDelete, rbac.ResourceSystem); err != nil {
11491149
return err
11501150
}
1151-
return q.db.DeleteOldWorkspaceAgentLogs(ctx)
1151+
return q.db.DeleteOldWorkspaceAgentLogs(ctx, threshold)
11521152
}
11531153

11541154
func (q *querier) DeleteOldWorkspaceAgentStats(ctx context.Context) error {

coderd/database/dbauthz/dbauthz_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2517,7 +2517,7 @@ func (s *MethodTestSuite) TestSystemFunctions() {
25172517
}).Asserts(rbac.ResourceSystem, policy.ActionCreate)
25182518
}))
25192519
s.Run("DeleteOldWorkspaceAgentLogs", s.Subtest(func(db database.Store, check *expects) {
2520-
check.Args().Asserts(rbac.ResourceSystem, policy.ActionDelete)
2520+
check.Args(time.Time{}).Asserts(rbac.ResourceSystem, policy.ActionDelete)
25212521
}))
25222522
s.Run("InsertWorkspaceAgentStats", s.Subtest(func(db database.Store, check *expects) {
25232523
check.Args(database.InsertWorkspaceAgentStatsParams{}).Asserts(rbac.ResourceSystem, policy.ActionCreate).Errors(errMatchAny)

coderd/database/dbmem/dbmem.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,19 +1706,15 @@ func (q *FakeQuerier) DeleteOldProvisionerDaemons(_ context.Context) error {
17061706
return nil
17071707
}
17081708

1709-
func (q *FakeQuerier) DeleteOldWorkspaceAgentLogs(_ context.Context) error {
1709+
func (q *FakeQuerier) DeleteOldWorkspaceAgentLogs(_ context.Context, threshold time.Time) error {
17101710
q.mutex.Lock()
17111711
defer q.mutex.Unlock()
17121712

1713-
now := dbtime.Now()
1714-
weekInterval := 7 * 24 * time.Hour
1715-
weekAgo := now.Add(-weekInterval)
1716-
17171713
var validLogs []database.WorkspaceAgentLog
17181714
for _, log := range q.workspaceAgentLogs {
17191715
var toBeDeleted bool
17201716
for _, agent := range q.workspaceAgents {
1721-
if agent.ID == log.AgentID && agent.LastConnectedAt.Valid && agent.LastConnectedAt.Time.Before(weekAgo) {
1717+
if agent.ID == log.AgentID && agent.LastConnectedAt.Valid && agent.LastConnectedAt.Time.Before(threshold) {
17221718
toBeDeleted = true
17231719
break
17241720
}

coderd/database/dbmetrics/dbmetrics.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbmock/dbmock.go

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbpurge/dbpurge.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,28 @@ import (
1111

1212
"github.com/coder/coder/v2/coderd/database"
1313
"github.com/coder/coder/v2/coderd/database/dbauthz"
14+
"github.com/coder/quartz"
1415
)
1516

1617
const (
17-
delay = 10 * time.Minute
18+
delay = 10 * time.Minute
19+
maxAgentLogAge = 7 * 24 * time.Hour
1820
)
1921

2022
// New creates a new periodically purging database instance.
2123
// It is the caller's responsibility to call Close on the returned instance.
2224
//
2325
// This is for cleaning up old, unused resources from the database that take up space.
24-
func New(ctx context.Context, logger slog.Logger, db database.Store) io.Closer {
26+
func New(ctx context.Context, logger slog.Logger, db database.Store, clk quartz.Clock) io.Closer {
2527
closed := make(chan struct{})
2628

2729
ctx, cancelFunc := context.WithCancel(ctx)
2830
//nolint:gocritic // The system purges old db records without user input.
2931
ctx = dbauthz.AsSystemRestricted(ctx)
3032

31-
// Use time.Nanosecond to force an initial tick. It will be reset to the
32-
// correct duration after executing once.
33-
ticker := time.NewTicker(time.Nanosecond)
34-
doTick := func() {
33+
ticker := clk.NewTicker(time.Nanosecond)
34+
doTick := func(start time.Time) {
3535
defer ticker.Reset(delay)
36-
37-
start := time.Now()
3836
// Start a transaction to grab advisory lock, we don't want to run
3937
// multiple purges at the same time (multiple replicas).
4038
if err := db.InTx(func(tx database.Store) error {
@@ -49,7 +47,7 @@ func New(ctx context.Context, logger slog.Logger, db database.Store) io.Closer {
4947
return nil
5048
}
5149

52-
if err := tx.DeleteOldWorkspaceAgentLogs(ctx); err != nil {
50+
if err := tx.DeleteOldWorkspaceAgentLogs(ctx, start.Add(-maxAgentLogAge)); err != nil {
5351
return xerrors.Errorf("failed to delete old workspace agent logs: %w", err)
5452
}
5553
if err := tx.DeleteOldWorkspaceAgentStats(ctx); err != nil {
@@ -62,7 +60,7 @@ func New(ctx context.Context, logger slog.Logger, db database.Store) io.Closer {
6260
return xerrors.Errorf("failed to delete old notification messages: %w", err)
6361
}
6462

65-
logger.Info(ctx, "purged old database entries", slog.F("duration", time.Since(start)))
63+
logger.Info(ctx, "purged old database entries", slog.F("duration", clk.Since(start)))
6664

6765
return nil
6866
}, nil); err != nil {
@@ -78,9 +76,9 @@ func New(ctx context.Context, logger slog.Logger, db database.Store) io.Closer {
7876
select {
7977
case <-ctx.Done():
8078
return
81-
case <-ticker.C:
79+
case tick := <-ticker.C:
8280
ticker.Stop()
83-
doTick()
81+
doTick(tick)
8482
}
8583
}
8684
}()

0 commit comments

Comments
 (0)