@@ -140,42 +140,45 @@ func (e *Executor) runOnce(t time.Time) Stats {
140
140
141
141
eg .Go (func () error {
142
142
var job * database.ProvisionerJob
143
+ var auditLog * auditParams
143
144
err := e .db .InTx (func (tx database.Store ) error {
144
145
// Re-check eligibility since the first check was outside the
145
146
// transaction and the workspace settings may have changed.
146
147
ws , err := tx .GetWorkspaceByID (e .ctx , wsID )
147
148
if err != nil {
148
- log .Error (e .ctx , "get workspace autostart failed" , slog .Error (err ))
149
- return nil
149
+ return xerrors .Errorf ("get workspace by id: %w" , err )
150
150
}
151
151
152
152
// Determine the workspace state based on its latest build.
153
153
latestBuild , err := tx .GetLatestWorkspaceBuildByWorkspaceID (e .ctx , ws .ID )
154
154
if err != nil {
155
- log .Warn (e .ctx , "get latest workspace build" , slog .Error (err ))
156
- return nil
155
+ return xerrors .Errorf ("get latest workspace build: %w" , err )
157
156
}
158
- templateSchedule , err := (* (e .templateScheduleStore .Load ())).Get (e .ctx , tx , ws .TemplateID )
157
+
158
+ latestJob , err := tx .GetProvisionerJobByID (e .ctx , latestBuild .JobID )
159
159
if err != nil {
160
- log .Warn (e .ctx , "get template schedule options" , slog .Error (err ))
161
- return nil
160
+ return xerrors .Errorf ("get latest provisioner job: %w" , err )
162
161
}
163
162
164
- template , err := tx . GetTemplateByID ( e .ctx , ws .TemplateID )
163
+ templateSchedule , err := ( * ( e . templateScheduleStore . Load ())). Get ( e .ctx , tx , ws .TemplateID )
165
164
if err != nil {
166
- log . Warn ( e . ctx , "get template by id " , slog . Error ( err ) )
165
+ return xerrors . Errorf ( "get template scheduling options: %w " , err )
167
166
}
168
- accessControl := (* (e .accessControlStore .Load ())).GetTemplateAccessControl (template )
169
167
170
- latestJob , err := tx .GetProvisionerJobByID (e .ctx , latestBuild . JobID )
168
+ template , err := tx .GetTemplateByID (e .ctx , ws . TemplateID )
171
169
if err != nil {
172
- log .Warn (e .ctx , "get last provisioner job for workspace %q: %w" , slog .Error (err ))
173
- return nil
170
+ return xerrors .Errorf ("get template by ID: %w" , err )
174
171
}
175
172
173
+ accessControl := (* (e .accessControlStore .Load ())).GetTemplateAccessControl (template )
174
+
176
175
nextTransition , reason , err := getNextTransition (ws , latestBuild , latestJob , templateSchedule , currentTick )
177
176
if err != nil {
178
177
log .Debug (e .ctx , "skipping workspace" , slog .Error (err ))
178
+ // err is used to indicate that a workspace is not eligible
179
+ // so returning nil here is ok although ultimately the distinction
180
+ // doesn't matter since the transaction is read-only up to
181
+ // this point.
179
182
return nil
180
183
}
181
184
@@ -193,17 +196,16 @@ func (e *Executor) runOnce(t time.Time) Stats {
193
196
}
194
197
195
198
build , job , err = builder .Build (e .ctx , tx , nil , audit.WorkspaceBuildBaggage {IP : "127.0.0.1" })
196
-
197
199
if err != nil {
198
200
log .Error (e .ctx , "unable to transition workspace" ,
199
201
slog .F ("transition" , nextTransition ),
200
202
slog .Error (err ),
201
203
)
202
- return nil
204
+ return xerrors . Errorf ( "build workspace: %w" , err )
203
205
}
204
206
}
205
207
206
- // Transition the workspace to dormant if it has breached the template's
208
+ // Transition the workspace to dormant if it has breached the template's
207
209
// threshold for inactivity.
208
210
if reason == database .BuildReasonAutolock {
209
211
wsOld := ws
@@ -215,21 +217,15 @@ func (e *Executor) runOnce(t time.Time) Stats {
215
217
},
216
218
})
217
219
218
- auditBuild (e .ctx , e .log , * e .auditor .Load (), auditParams {
219
- Build : build ,
220
- Job : latestJob ,
221
- Reason : reason ,
222
- Old : wsOld ,
223
- New : ws ,
224
- Success : err == nil ,
225
- })
226
-
220
+ auditLog = & auditParams {
221
+ Build : build ,
222
+ Job : latestJob ,
223
+ Reason : reason ,
224
+ Old : wsOld ,
225
+ New : ws ,
226
+ }
227
227
if err != nil {
228
- log .Error (e .ctx , "unable to transition workspace to dormant" ,
229
- slog .F ("transition" , nextTransition ),
230
- slog .Error (err ),
231
- )
232
- return nil
228
+ return xerrors .Errorf ("update workspace dormant deleting at: %w" , err )
233
229
}
234
230
235
231
log .Info (e .ctx , "dormant workspace" ,
@@ -267,6 +263,12 @@ func (e *Executor) runOnce(t time.Time) Stats {
267
263
if err != nil {
268
264
log .Error (e .ctx , "workspace scheduling failed" , slog .Error (err ))
269
265
}
266
+ if auditLog != nil {
267
+ // If the transition didn't succeed then updating the workspace
268
+ // to indicate dormant didn't either.
269
+ auditLog .Success = err == nil
270
+ auditBuild (e .ctx , e .log , * e .auditor .Load (), * auditLog )
271
+ }
270
272
if job != nil && err == nil {
271
273
// Note that we can't refactor such that posting the job happens inside wsbuilder because it's called
272
274
// with an outer transaction like this, and we need to make sure the outer transaction commits before
0 commit comments