Skip to content

Commit 0896f33

Browse files
refactor(coderd/provisionerdserver): use quartz.Clock instead of TimeNowFn (#15642)
Replace `TimeNowFn` in `provisionerdserver` with `quartz.Clock` as well as pass `coderd`'s `Clock` to `provisionerdserver`.
1 parent bbc549d commit 0896f33

File tree

4 files changed

+36
-32
lines changed

4 files changed

+36
-32
lines changed

coderd/coderd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,6 +1648,7 @@ func (api *API) CreateInMemoryTaggedProvisionerDaemon(dialCtx context.Context, n
16481648
provisionerdserver.Options{
16491649
OIDCConfig: api.OIDCConfig,
16501650
ExternalAuthConfigs: api.ExternalAuthConfigs,
1651+
Clock: api.Clock,
16511652
},
16521653
api.NotificationsEnqueuer,
16531654
)

coderd/provisionerdserver/provisionerdserver.go

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import (
4646
"github.com/coder/coder/v2/provisionerd/proto"
4747
"github.com/coder/coder/v2/provisionersdk"
4848
sdkproto "github.com/coder/coder/v2/provisionersdk/proto"
49+
"github.com/coder/quartz"
4950
)
5051

5152
const (
@@ -61,8 +62,9 @@ const (
6162
type Options struct {
6263
OIDCConfig promoauth.OAuth2Config
6364
ExternalAuthConfigs []*externalauth.Config
64-
// TimeNowFn is only used in tests
65-
TimeNowFn func() time.Time
65+
66+
// Clock for testing
67+
Clock quartz.Clock
6668

6769
// AcquireJobLongPollDur is used in tests
6870
AcquireJobLongPollDur time.Duration
@@ -104,7 +106,7 @@ type server struct {
104106

105107
OIDCConfig promoauth.OAuth2Config
106108

107-
TimeNowFn func() time.Time
109+
Clock quartz.Clock
108110

109111
acquireJobLongPollDur time.Duration
110112

@@ -191,6 +193,9 @@ func NewServer(
191193
if options.HeartbeatInterval == 0 {
192194
options.HeartbeatInterval = DefaultHeartbeatInterval
193195
}
196+
if options.Clock == nil {
197+
options.Clock = quartz.NewReal()
198+
}
194199

195200
s := &server{
196201
lifecycleCtx: lifecycleCtx,
@@ -213,7 +218,7 @@ func NewServer(
213218
UserQuietHoursScheduleStore: userQuietHoursScheduleStore,
214219
DeploymentValues: deploymentValues,
215220
OIDCConfig: options.OIDCConfig,
216-
TimeNowFn: options.TimeNowFn,
221+
Clock: options.Clock,
217222
acquireJobLongPollDur: options.AcquireJobLongPollDur,
218223
heartbeatInterval: options.HeartbeatInterval,
219224
heartbeatFn: options.HeartbeatFn,
@@ -229,11 +234,8 @@ func NewServer(
229234

230235
// timeNow should be used when trying to get the current time for math
231236
// calculations regarding workspace start and stop time.
232-
func (s *server) timeNow() time.Time {
233-
if s.TimeNowFn != nil {
234-
return dbtime.Time(s.TimeNowFn())
235-
}
236-
return dbtime.Now()
237+
func (s *server) timeNow(tags ...string) time.Time {
238+
return dbtime.Time(s.Clock.Now(tags...))
237239
}
238240

239241
// heartbeatLoop runs heartbeatOnce at the interval specified by HeartbeatInterval
@@ -365,7 +367,7 @@ func (s *server) AcquireJobWithCancel(stream proto.DRPCProvisionerDaemon_Acquire
365367
logger.Error(streamCtx, "recv error and failed to cancel acquire job", slog.Error(recvErr))
366368
// Well, this is awkward. We hit an error receiving from the stream, but didn't cancel before we locked a job
367369
// in the database. We need to mark this job as failed so the end user can retry if they want to.
368-
now := dbtime.Now()
370+
now := s.timeNow()
369371
err := s.Database.UpdateProvisionerJobWithCompleteByID(
370372
//nolint:gocritic // Provisionerd has specific authz rules.
371373
dbauthz.AsProvisionerd(context.Background()),
@@ -406,15 +408,15 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo
406408
err := s.Database.UpdateProvisionerJobWithCompleteByID(ctx, database.UpdateProvisionerJobWithCompleteByIDParams{
407409
ID: job.ID,
408410
CompletedAt: sql.NullTime{
409-
Time: dbtime.Now(),
411+
Time: s.timeNow(),
410412
Valid: true,
411413
},
412414
Error: sql.NullString{
413415
String: errorMessage,
414416
Valid: true,
415417
},
416418
ErrorCode: job.ErrorCode,
417-
UpdatedAt: dbtime.Now(),
419+
UpdatedAt: s.timeNow(),
418420
})
419421
if err != nil {
420422
return xerrors.Errorf("update provisioner job: %w", err)
@@ -792,7 +794,7 @@ func (s *server) UpdateJob(ctx context.Context, request *proto.UpdateJobRequest)
792794
}
793795
err = s.Database.UpdateProvisionerJobByID(ctx, database.UpdateProvisionerJobByIDParams{
794796
ID: parsedID,
795-
UpdatedAt: dbtime.Now(),
797+
UpdatedAt: s.timeNow(),
796798
})
797799
if err != nil {
798800
return nil, xerrors.Errorf("update job: %w", err)
@@ -869,7 +871,7 @@ func (s *server) UpdateJob(ctx context.Context, request *proto.UpdateJobRequest)
869871
err := s.Database.UpdateTemplateVersionDescriptionByJobID(ctx, database.UpdateTemplateVersionDescriptionByJobIDParams{
870872
JobID: job.ID,
871873
Readme: string(request.Readme),
872-
UpdatedAt: dbtime.Now(),
874+
UpdatedAt: s.timeNow(),
873875
})
874876
if err != nil {
875877
return nil, xerrors.Errorf("update template version description: %w", err)
@@ -958,7 +960,7 @@ func (s *server) FailJob(ctx context.Context, failJob *proto.FailedJob) (*proto.
958960
return nil, xerrors.Errorf("job already completed")
959961
}
960962
job.CompletedAt = sql.NullTime{
961-
Time: dbtime.Now(),
963+
Time: s.timeNow(),
962964
Valid: true,
963965
}
964966
job.Error = sql.NullString{
@@ -973,7 +975,7 @@ func (s *server) FailJob(ctx context.Context, failJob *proto.FailedJob) (*proto.
973975
err = s.Database.UpdateProvisionerJobWithCompleteByID(ctx, database.UpdateProvisionerJobWithCompleteByIDParams{
974976
ID: jobID,
975977
CompletedAt: job.CompletedAt,
976-
UpdatedAt: dbtime.Now(),
978+
UpdatedAt: s.timeNow(),
977979
Error: job.Error,
978980
ErrorCode: job.ErrorCode,
979981
})
@@ -1008,15 +1010,15 @@ func (s *server) FailJob(ctx context.Context, failJob *proto.FailedJob) (*proto.
10081010
if jobType.WorkspaceBuild.State != nil {
10091011
err = db.UpdateWorkspaceBuildProvisionerStateByID(ctx, database.UpdateWorkspaceBuildProvisionerStateByIDParams{
10101012
ID: input.WorkspaceBuildID,
1011-
UpdatedAt: dbtime.Now(),
1013+
UpdatedAt: s.timeNow(),
10121014
ProvisionerState: jobType.WorkspaceBuild.State,
10131015
})
10141016
if err != nil {
10151017
return xerrors.Errorf("update workspace build state: %w", err)
10161018
}
10171019
err = db.UpdateWorkspaceBuildDeadlineByID(ctx, database.UpdateWorkspaceBuildDeadlineByIDParams{
10181020
ID: input.WorkspaceBuildID,
1019-
UpdatedAt: dbtime.Now(),
1021+
UpdatedAt: s.timeNow(),
10201022
Deadline: build.Deadline,
10211023
MaxDeadline: build.MaxDeadline,
10221024
})
@@ -1382,17 +1384,17 @@ func (s *server) CompleteJob(ctx context.Context, completed *proto.CompletedJob)
13821384
err = s.Database.UpdateTemplateVersionExternalAuthProvidersByJobID(ctx, database.UpdateTemplateVersionExternalAuthProvidersByJobIDParams{
13831385
JobID: jobID,
13841386
ExternalAuthProviders: json.RawMessage(externalAuthProvidersMessage),
1385-
UpdatedAt: dbtime.Now(),
1387+
UpdatedAt: s.timeNow(),
13861388
})
13871389
if err != nil {
13881390
return nil, xerrors.Errorf("update template version external auth providers: %w", err)
13891391
}
13901392

13911393
err = s.Database.UpdateProvisionerJobWithCompleteByID(ctx, database.UpdateProvisionerJobWithCompleteByIDParams{
13921394
ID: jobID,
1393-
UpdatedAt: dbtime.Now(),
1395+
UpdatedAt: s.timeNow(),
13941396
CompletedAt: sql.NullTime{
1395-
Time: dbtime.Now(),
1397+
Time: s.timeNow(),
13961398
Valid: true,
13971399
},
13981400
Error: completedError,
@@ -1687,9 +1689,9 @@ func (s *server) CompleteJob(ctx context.Context, completed *proto.CompletedJob)
16871689

16881690
err = s.Database.UpdateProvisionerJobWithCompleteByID(ctx, database.UpdateProvisionerJobWithCompleteByIDParams{
16891691
ID: jobID,
1690-
UpdatedAt: dbtime.Now(),
1692+
UpdatedAt: s.timeNow(),
16911693
CompletedAt: sql.NullTime{
1692-
Time: dbtime.Now(),
1694+
Time: s.timeNow(),
16931695
Valid: true,
16941696
},
16951697
Error: sql.NullString{},

coderd/provisionerdserver/provisionerdserver_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"storj.io/drpc"
2323

2424
"cdr.dev/slog/sloggers/slogtest"
25+
"github.com/coder/quartz"
2526
"github.com/coder/serpent"
2627

2728
"github.com/coder/coder/v2/buildinfo"
@@ -1211,14 +1212,13 @@ func TestCompleteJob(t *testing.T) {
12111212

12121213
// Simulate the given time starting from now.
12131214
require.False(t, c.now.IsZero())
1214-
start := time.Now()
1215+
clock := quartz.NewMock(t)
1216+
clock.Set(c.now)
12151217
tss := &atomic.Pointer[schedule.TemplateScheduleStore]{}
12161218
uqhss := &atomic.Pointer[schedule.UserQuietHoursScheduleStore]{}
12171219
auditor := audit.NewMock()
12181220
srv, db, ps, pd := setup(t, false, &overrides{
1219-
timeNowFn: func() time.Time {
1220-
return c.now.Add(time.Since(start))
1221-
},
1221+
clock: clock,
12221222
templateScheduleStore: tss,
12231223
userQuietHoursScheduleStore: uqhss,
12241224
auditor: auditor,
@@ -2189,7 +2189,7 @@ type overrides struct {
21892189
externalAuthConfigs []*externalauth.Config
21902190
templateScheduleStore *atomic.Pointer[schedule.TemplateScheduleStore]
21912191
userQuietHoursScheduleStore *atomic.Pointer[schedule.UserQuietHoursScheduleStore]
2192-
timeNowFn func() time.Time
2192+
clock *quartz.Mock
21932193
acquireJobLongPollDuration time.Duration
21942194
heartbeatFn func(ctx context.Context) error
21952195
heartbeatInterval time.Duration
@@ -2209,7 +2209,7 @@ func setup(t *testing.T, ignoreLogErrors bool, ov *overrides) (proto.DRPCProvisi
22092209
var externalAuthConfigs []*externalauth.Config
22102210
tss := testTemplateScheduleStore()
22112211
uqhss := testUserQuietHoursScheduleStore()
2212-
var timeNowFn func() time.Time
2212+
clock := quartz.NewReal()
22132213
pollDur := time.Duration(0)
22142214
if ov == nil {
22152215
ov = &overrides{}
@@ -2246,8 +2246,8 @@ func setup(t *testing.T, ignoreLogErrors bool, ov *overrides) (proto.DRPCProvisi
22462246
require.True(t, swapped)
22472247
}
22482248
}
2249-
if ov.timeNowFn != nil {
2250-
timeNowFn = ov.timeNowFn
2249+
if ov.clock != nil {
2250+
clock = ov.clock
22512251
}
22522252
auditPtr := &atomic.Pointer[audit.Auditor]{}
22532253
var auditor audit.Auditor = audit.NewMock()
@@ -2296,7 +2296,7 @@ func setup(t *testing.T, ignoreLogErrors bool, ov *overrides) (proto.DRPCProvisi
22962296
deploymentValues,
22972297
provisionerdserver.Options{
22982298
ExternalAuthConfigs: externalAuthConfigs,
2299-
TimeNowFn: timeNowFn,
2299+
Clock: clock,
23002300
OIDCConfig: &oauth2.Config{},
23012301
AcquireJobLongPollDur: pollDur,
23022302
HeartbeatInterval: ov.heartbeatInterval,

enterprise/coderd/provisionerdaemons.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ func (api *API) provisionerDaemonServe(rw http.ResponseWriter, r *http.Request)
403403
provisionerdserver.Options{
404404
ExternalAuthConfigs: api.ExternalAuthConfigs,
405405
OIDCConfig: api.OIDCConfig,
406+
Clock: api.Clock,
406407
},
407408
api.NotificationsEnqueuer,
408409
)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy