@@ -51,9 +51,8 @@ func New(clientDialer Dialer, opts *Options) io.Closer {
51
51
clientDialer : clientDialer ,
52
52
opts : opts ,
53
53
54
- closeContext : ctx ,
55
- closeCancel : ctxCancel ,
56
- closed : make (chan struct {}),
54
+ closeCancel : ctxCancel ,
55
+ closed : make (chan struct {}),
57
56
58
57
jobRunning : make (chan struct {}),
59
58
}
@@ -71,23 +70,21 @@ type provisionerDaemon struct {
71
70
client proto.DRPCProvisionerDaemonClient
72
71
updateStream proto.DRPCProvisionerDaemon_UpdateJobClient
73
72
74
- closeContext context. Context
75
- closeCancel context. CancelFunc
76
- closed chan struct {}
77
- closeMutex sync. Mutex
78
- closeError error
73
+ // Locked when closing the daemon.
74
+ closeMutex sync. Mutex
75
+ closeCancel context. CancelFunc
76
+ closed chan struct {}
77
+ closeError error
79
78
80
- jobID string
79
+ // Locked when acquiring or canceling a job.
81
80
jobMutex sync.Mutex
81
+ jobID string
82
82
jobRunning chan struct {}
83
83
jobCancel context.CancelFunc
84
84
}
85
85
86
86
// Connect establishes a connection to coderd.
87
87
func (p * provisionerDaemon ) connect (ctx context.Context ) {
88
- p .jobMutex .Lock ()
89
- defer p .jobMutex .Unlock ()
90
-
91
88
var err error
92
89
// An exponential back-off occurs when the connection is failing to dial.
93
90
// This is to prevent server spam in case of a coderd outage.
@@ -102,6 +99,9 @@ func (p *provisionerDaemon) connect(ctx context.Context) {
102
99
}
103
100
p .updateStream , err = p .client .UpdateJob (ctx )
104
101
if err != nil {
102
+ if errors .Is (err , context .Canceled ) {
103
+ return
104
+ }
105
105
p .opts .Logger .Warn (context .Background (), "create update job stream" , slog .Error (err ))
106
106
continue
107
107
}
@@ -126,12 +126,6 @@ func (p *provisionerDaemon) connect(ctx context.Context) {
126
126
// has been interrupted. This works well, because logs need
127
127
// to buffer if a job is running in the background.
128
128
p .opts .Logger .Debug (context .Background (), "update stream ended" , slog .Error (p .updateStream .Context ().Err ()))
129
- // Make sure we're not closing here!
130
- p .closeMutex .Lock ()
131
- defer p .closeMutex .Unlock ()
132
- if p .isClosed () {
133
- return
134
- }
135
129
p .connect (ctx )
136
130
}
137
131
}()
@@ -168,6 +162,9 @@ func (p *provisionerDaemon) isRunningJob() bool {
168
162
func (p * provisionerDaemon ) acquireJob (ctx context.Context ) {
169
163
p .jobMutex .Lock ()
170
164
defer p .jobMutex .Unlock ()
165
+ if p .isClosed () {
166
+ return
167
+ }
171
168
if p .isRunningJob () {
172
169
p .opts .Logger .Debug (context .Background (), "skipping acquire; job is already running" )
173
170
return
@@ -184,15 +181,10 @@ func (p *provisionerDaemon) acquireJob(ctx context.Context) {
184
181
p .opts .Logger .Warn (context .Background (), "acquire job" , slog .Error (err ))
185
182
return
186
183
}
187
- if p .isClosed () {
188
- return
189
- }
190
184
if job .JobId == "" {
191
185
p .opts .Logger .Debug (context .Background (), "no jobs available" )
192
186
return
193
187
}
194
- p .closeMutex .Lock ()
195
- defer p .closeMutex .Unlock ()
196
188
ctx , p .jobCancel = context .WithCancel (ctx )
197
189
p .jobRunning = make (chan struct {})
198
190
p .jobID = job .JobId
@@ -222,31 +214,27 @@ func (p *provisionerDaemon) runJob(ctx context.Context, job *proto.AcquiredJob)
222
214
JobId : job .JobId ,
223
215
})
224
216
if err != nil {
225
- go p .cancelActiveJob ( fmt . Sprintf ( "send periodic update: %s" , err ) )
217
+ go p .cancelActiveJobf ( "send periodic update: %s" , err )
226
218
return
227
219
}
228
220
}
229
221
}()
230
222
defer func () {
231
223
// Cleanup the work directory after execution.
232
224
err := os .RemoveAll (p .opts .WorkDirectory )
233
- if err != nil {
234
- go p .cancelActiveJob (fmt .Sprintf ("remove all from %q directory: %s" , p .opts .WorkDirectory , err ))
235
- return
236
- }
237
- p .opts .Logger .Debug (ctx , "cleaned up work directory" )
225
+ p .opts .Logger .Debug (ctx , "cleaned up work directory" , slog .Error (err ))
238
226
close (p .jobRunning )
239
227
}()
240
228
// It's safe to cast this ProvisionerType. This data is coming directly from coderd.
241
229
provisioner , hasProvisioner := p .opts .Provisioners [job .Provisioner ]
242
230
if ! hasProvisioner {
243
- go p .cancelActiveJob ( fmt . Sprintf ( "provisioner %q not registered" , job .Provisioner ) )
231
+ go p .cancelActiveJobf ( "provisioner %q not registered" , job .Provisioner )
244
232
return
245
233
}
246
234
247
235
err := os .MkdirAll (p .opts .WorkDirectory , 0700 )
248
236
if err != nil {
249
- go p .cancelActiveJob ( fmt . Sprintf ( "create work directory %q: %s" , p .opts .WorkDirectory , err ) )
237
+ go p .cancelActiveJobf ( "create work directory %q: %s" , p .opts .WorkDirectory , err )
250
238
return
251
239
}
252
240
@@ -258,13 +246,13 @@ func (p *provisionerDaemon) runJob(ctx context.Context, job *proto.AcquiredJob)
258
246
break
259
247
}
260
248
if err != nil {
261
- go p .cancelActiveJob ( fmt . Sprintf ( "read project source archive: %s" , err ) )
249
+ go p .cancelActiveJobf ( "read project source archive: %s" , err )
262
250
return
263
251
}
264
252
// #nosec
265
253
path := filepath .Join (p .opts .WorkDirectory , header .Name )
266
254
if ! strings .HasPrefix (path , filepath .Clean (p .opts .WorkDirectory )) {
267
- go p .cancelActiveJob ("tar attempts to target relative upper directory" )
255
+ go p .cancelActiveJobf ("tar attempts to target relative upper directory" )
268
256
return
269
257
}
270
258
mode := header .FileInfo ().Mode ()
@@ -275,14 +263,14 @@ func (p *provisionerDaemon) runJob(ctx context.Context, job *proto.AcquiredJob)
275
263
case tar .TypeDir :
276
264
err = os .MkdirAll (path , mode )
277
265
if err != nil {
278
- go p .cancelActiveJob ( fmt . Sprintf ( "mkdir %q: %s" , path , err ) )
266
+ go p .cancelActiveJobf ( "mkdir %q: %s" , path , err )
279
267
return
280
268
}
281
269
p .opts .Logger .Debug (context .Background (), "extracted directory" , slog .F ("path" , path ))
282
270
case tar .TypeReg :
283
271
file , err := os .OpenFile (path , os .O_CREATE | os .O_RDWR , mode )
284
272
if err != nil {
285
- go p .cancelActiveJob ( fmt . Sprintf ( "create file %q (mode %s): %s" , path , mode , err ) )
273
+ go p .cancelActiveJobf ( "create file %q (mode %s): %s" , path , mode , err )
286
274
return
287
275
}
288
276
// Max file size of 10MB.
@@ -291,12 +279,12 @@ func (p *provisionerDaemon) runJob(ctx context.Context, job *proto.AcquiredJob)
291
279
err = nil
292
280
}
293
281
if err != nil {
294
- go p .cancelActiveJob ( fmt . Sprintf ( "copy file %q: %s" , path , err ) )
282
+ go p .cancelActiveJobf ( "copy file %q: %s" , path , err )
295
283
return
296
284
}
297
285
err = file .Close ()
298
286
if err != nil {
299
- go p .cancelActiveJob ( fmt . Sprintf ( "close file %q: %s" , path , err ) )
287
+ go p .cancelActiveJobf ( "close file %q: %s" , path , err )
300
288
return
301
289
}
302
290
p .opts .Logger .Debug (context .Background (), "extracted file" ,
@@ -323,7 +311,7 @@ func (p *provisionerDaemon) runJob(ctx context.Context, job *proto.AcquiredJob)
323
311
324
312
p .runWorkspaceProvision (ctx , provisioner , job )
325
313
default :
326
- go p .cancelActiveJob ( fmt . Sprintf ( "unknown job type %q; ensure your provisioner daemon is up-to-date" , reflect .TypeOf (job .Type ).String () ))
314
+ go p .cancelActiveJobf ( "unknown job type %q; ensure your provisioner daemon is up-to-date" , reflect .TypeOf (job .Type ).String ())
327
315
return
328
316
}
329
317
@@ -335,14 +323,14 @@ func (p *provisionerDaemon) runProjectImport(ctx context.Context, provisioner sd
335
323
Directory : p .opts .WorkDirectory ,
336
324
})
337
325
if err != nil {
338
- go p .cancelActiveJob ( fmt . Sprintf ( "parse source: %s" , err ) )
326
+ go p .cancelActiveJobf ( "parse source: %s" , err )
339
327
return
340
328
}
341
329
defer stream .Close ()
342
330
for {
343
331
msg , err := stream .Recv ()
344
332
if err != nil {
345
- go p .cancelActiveJob ( fmt . Sprintf ( "recv parse source: %s" , err ) )
333
+ go p .cancelActiveJobf ( "recv parse source: %s" , err )
346
334
return
347
335
}
348
336
switch msgType := msg .Type .(type ) {
@@ -363,7 +351,7 @@ func (p *provisionerDaemon) runProjectImport(ctx context.Context, provisioner sd
363
351
}},
364
352
})
365
353
if err != nil {
366
- go p .cancelActiveJob ( fmt . Sprintf ( "update job: %s" , err ) )
354
+ go p .cancelActiveJobf ( "update job: %s" , err )
367
355
return
368
356
}
369
357
case * sdkproto.Parse_Response_Complete :
@@ -379,14 +367,14 @@ func (p *provisionerDaemon) runProjectImport(ctx context.Context, provisioner sd
379
367
},
380
368
})
381
369
if err != nil {
382
- go p .cancelActiveJob ( fmt . Sprintf ( "complete job: %s" , err ) )
370
+ go p .cancelActiveJobf ( "complete job: %s" , err )
383
371
return
384
372
}
385
373
// Return so we stop looping!
386
374
return
387
375
default :
388
- go p .cancelActiveJob ( fmt . Sprintf ("invalid message type %q received from provisioner" ,
389
- reflect .TypeOf (msg .Type ).String ()))
376
+ go p .cancelActiveJobf ("invalid message type %q received from provisioner" ,
377
+ reflect .TypeOf (msg .Type ).String ())
390
378
return
391
379
}
392
380
}
@@ -399,15 +387,15 @@ func (p *provisionerDaemon) runWorkspaceProvision(ctx context.Context, provision
399
387
State : job .GetWorkspaceProvision ().State ,
400
388
})
401
389
if err != nil {
402
- go p .cancelActiveJob ( fmt . Sprintf ( "provision: %s" , err ) )
390
+ go p .cancelActiveJobf ( "provision: %s" , err )
403
391
return
404
392
}
405
393
defer stream .Close ()
406
394
407
395
for {
408
396
msg , err := stream .Recv ()
409
397
if err != nil {
410
- go p .cancelActiveJob ( fmt . Sprintf ( "recv workspace provision: %s" , err ) )
398
+ go p .cancelActiveJobf ( "recv workspace provision: %s" , err )
411
399
return
412
400
}
413
401
switch msgType := msg .Type .(type ) {
@@ -428,7 +416,7 @@ func (p *provisionerDaemon) runWorkspaceProvision(ctx context.Context, provision
428
416
}},
429
417
})
430
418
if err != nil {
431
- go p .cancelActiveJob ( fmt . Sprintf ( "send job update: %s" , err ) )
419
+ go p .cancelActiveJobf ( "send job update: %s" , err )
432
420
return
433
421
}
434
422
case * sdkproto.Provision_Response_Complete :
@@ -450,26 +438,28 @@ func (p *provisionerDaemon) runWorkspaceProvision(ctx context.Context, provision
450
438
},
451
439
})
452
440
if err != nil {
453
- go p .cancelActiveJob ( fmt . Sprintf ( "complete job: %s" , err ) )
441
+ go p .cancelActiveJobf ( "complete job: %s" , err )
454
442
return
455
443
}
456
444
// Return so we stop looping!
457
445
return
458
446
default :
459
- go p .cancelActiveJob ( fmt . Sprintf ("invalid message type %q received from provisioner" ,
460
- reflect .TypeOf (msg .Type ).String ()))
447
+ go p .cancelActiveJobf ("invalid message type %q received from provisioner" ,
448
+ reflect .TypeOf (msg .Type ).String ())
461
449
return
462
450
}
463
451
}
464
452
}
465
453
466
- func (p * provisionerDaemon ) cancelActiveJob ( errMsg string ) {
454
+ func (p * provisionerDaemon ) cancelActiveJobf ( format string , args ... interface {} ) {
467
455
p .jobMutex .Lock ()
468
456
defer p .jobMutex .Unlock ()
469
- if p .isClosed () {
470
- return
471
- }
457
+ errMsg := fmt .Sprintf (format , args ... )
472
458
if ! p .isRunningJob () {
459
+ if p .isClosed () {
460
+ // We don't want to log if we're already closed!
461
+ return
462
+ }
473
463
p .opts .Logger .Warn (context .Background (), "skipping job cancel; none running" , slog .F ("error_message" , errMsg ))
474
464
return
475
465
}
@@ -512,22 +502,20 @@ func (p *provisionerDaemon) closeWithError(err error) error {
512
502
if p .isClosed () {
513
503
return p .closeError
514
504
}
515
- p .closeCancel ()
505
+ p .closeError = err
506
+ close (p .closed )
507
+
516
508
errMsg := "provisioner daemon was shutdown gracefully"
517
509
if err != nil {
518
510
errMsg = err .Error ()
519
511
}
520
- p .cancelActiveJob (errMsg )
521
- p .jobMutex .Lock ()
522
- defer p .jobMutex .Unlock ()
523
- p .opts .Logger .Debug (context .Background (), "closing server with error" , slog .Error (err ))
524
- p .closeError = err
525
- close (p .closed )
512
+ p .cancelActiveJobf (errMsg )
513
+ p .closeCancel ()
526
514
527
- if p . updateStream != nil {
528
- _ = p . client . DRPCConn (). Close ()
529
- _ = p . updateStream . Close ( )
530
- }
515
+ // Required until we're on Go 1.18. See:
516
+ // https://github.com/golang/go/issues/50510
517
+ _ = os . RemoveAll ( p . opts . WorkDirectory )
518
+ p . opts . Logger . Debug ( context . Background (), "closing server with error" , slog . Error ( err ))
531
519
532
520
return err
533
521
}
0 commit comments