@@ -1322,6 +1322,101 @@ func TestQueuePosition(t *testing.T) {
1322
1322
}
1323
1323
}
1324
1324
1325
+ func TestAcquireProvisionerJob (t * testing.T ) {
1326
+ t .Parallel ()
1327
+
1328
+ t .Run ("HumanInitiatedJobsFirst" , func (t * testing.T ) {
1329
+ t .Parallel ()
1330
+ var (
1331
+ db , _ = dbtestutil .NewDB (t )
1332
+ ctx = testutil .Context (t , testutil .WaitMedium )
1333
+ org = dbgen .Organization (t , db , database.Organization {})
1334
+ _ = dbgen .ProvisionerDaemon (t , db , database.ProvisionerDaemon {}) // Required for queue position
1335
+ now = dbtime .Now ()
1336
+ numJobs = 10
1337
+ humanIDs = make ([]uuid.UUID , 0 , numJobs / 2 )
1338
+ prebuildIDs = make ([]uuid.UUID , 0 , numJobs / 2 )
1339
+ )
1340
+
1341
+ // Given: a number of jobs in the queue, with prebuilds and non-prebuilds interleaved
1342
+ for idx := range numJobs {
1343
+ var initiator uuid.UUID
1344
+ if idx % 2 == 0 {
1345
+ initiator = database .PrebuildsSystemUserID
1346
+ } else {
1347
+ initiator = uuid .MustParse ("c0dec0de-c0de-c0de-c0de-c0dec0dec0de" )
1348
+ }
1349
+ pj , err := db .InsertProvisionerJob (ctx , database.InsertProvisionerJobParams {
1350
+ ID : uuid .MustParse (fmt .Sprintf ("00000000-0000-0000-0000-00000000000%x" , idx + 1 )),
1351
+ CreatedAt : time .Now ().Add (- time .Second * time .Duration (idx )),
1352
+ UpdatedAt : time .Now ().Add (- time .Second * time .Duration (idx )),
1353
+ InitiatorID : initiator ,
1354
+ OrganizationID : org .ID ,
1355
+ Provisioner : database .ProvisionerTypeEcho ,
1356
+ Type : database .ProvisionerJobTypeWorkspaceBuild ,
1357
+ StorageMethod : database .ProvisionerStorageMethodFile ,
1358
+ FileID : uuid .New (),
1359
+ Input : json .RawMessage (`{}` ),
1360
+ Tags : database.StringMap {},
1361
+ TraceMetadata : pqtype.NullRawMessage {},
1362
+ })
1363
+ require .NoError (t , err )
1364
+ // We expected prebuilds to be acquired after human-initiated jobs.
1365
+ if initiator == database .PrebuildsSystemUserID {
1366
+ prebuildIDs = append ([]uuid.UUID {pj .ID }, prebuildIDs ... )
1367
+ } else {
1368
+ humanIDs = append ([]uuid.UUID {pj .ID }, humanIDs ... )
1369
+ }
1370
+ t .Logf ("created job id=%q initiator=%q created_at=%q" , pj .ID .String (), pj .InitiatorID .String (), pj .CreatedAt .String ())
1371
+ }
1372
+
1373
+ expectedIDs := append (humanIDs , prebuildIDs ... ) //nolint:gocritic // not the same slice
1374
+
1375
+ // When: we query the queue positions for the jobs
1376
+ qjs , err := db .GetProvisionerJobsByIDsWithQueuePosition (ctx , database.GetProvisionerJobsByIDsWithQueuePositionParams {
1377
+ IDs : expectedIDs ,
1378
+ StaleIntervalMS : provisionerdserver .StaleInterval .Milliseconds (),
1379
+ })
1380
+ require .NoError (t , err )
1381
+ require .Len (t , qjs , numJobs )
1382
+ // Ensure the jobs are sorted by queue position.
1383
+ sort .Slice (qjs , func (i , j int ) bool {
1384
+ return qjs [i ].QueuePosition < qjs [j ].QueuePosition
1385
+ })
1386
+
1387
+ // Then: the queue positions for the jobs should indicate the order in which
1388
+ // they will be acquired, with human-initiated jobs first.
1389
+ for idx , qj := range qjs {
1390
+ t .Logf ("queued job %d/%d id=%q initiator=%q created_at=%q queue_position=%d" , idx + 1 , numJobs , qj .ProvisionerJob .ID .String (), qj .ProvisionerJob .InitiatorID .String (), qj .ProvisionerJob .CreatedAt .String (), qj .QueuePosition )
1391
+ require .Equal (t , expectedIDs [idx ].String (), qj .ProvisionerJob .ID .String (), "job %d/%d should match expected id" , idx + 1 , numJobs )
1392
+ require .Equal (t , int64 (idx + 1 ), qj .QueuePosition , "job %d/%d should have queue position %d" , idx + 1 , numJobs , idx + 1 )
1393
+ }
1394
+
1395
+ // When: the jobs are acquired
1396
+ // Then: human-initiated jobs are prioritized first.
1397
+ for idx := range numJobs {
1398
+ acquired , err := db .AcquireProvisionerJob (ctx , database.AcquireProvisionerJobParams {
1399
+ OrganizationID : org .ID ,
1400
+ StartedAt : sql.NullTime {Time : time .Now (), Valid : true },
1401
+ WorkerID : uuid.NullUUID {UUID : uuid .New (), Valid : true },
1402
+ Types : []database.ProvisionerType {database .ProvisionerTypeEcho },
1403
+ ProvisionerTags : json .RawMessage (`{}` ),
1404
+ })
1405
+ require .NoError (t , err )
1406
+ require .Equal (t , expectedIDs [idx ].String (), acquired .ID .String (), "acquired job %d/%d with initiator %q" , idx + 1 , numJobs , acquired .InitiatorID .String ())
1407
+ t .Logf ("acquired job id=%q initiator=%q created_at=%q" , acquired .ID .String (), acquired .InitiatorID .String (), acquired .CreatedAt .String ())
1408
+ err = db .UpdateProvisionerJobWithCompleteByID (ctx , database.UpdateProvisionerJobWithCompleteByIDParams {
1409
+ ID : acquired .ID ,
1410
+ UpdatedAt : now ,
1411
+ CompletedAt : sql.NullTime {Time : now , Valid : true },
1412
+ Error : sql.NullString {},
1413
+ ErrorCode : sql.NullString {},
1414
+ })
1415
+ require .NoError (t , err , "mark job %d/%d as complete" , idx + 1 , numJobs )
1416
+ }
1417
+ })
1418
+ }
1419
+
1325
1420
func TestUserLastSeenFilter (t * testing.T ) {
1326
1421
t .Parallel ()
1327
1422
if testing .Short () {
0 commit comments