mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
fix(coderd/database/dbfake): prevent cross-test job stealing in WorkspaceBuildBuilder (#22598)
Previously, WorkspaceBuildBuilder.doInTX() inserted provisioner jobs with empty tags and used a loop in AcquireProvisionerJob that could match other tests' pending jobs when parallel tests share a database. Add a unique tag (jobID -> "true") to each provisioner job at insert time, then use that tag in AcquireProvisionerJob to target only the correct job. This follows the same pattern used in dbgen.ProvisionerJob. Closes coder/internal#1367
This commit is contained in:
committed by
GitHub
parent
1a30ca1a2a
commit
c7dd429bbf
@@ -372,6 +372,12 @@ func (b WorkspaceBuildBuilder) doInTX() WorkspaceResponse {
|
||||
})
|
||||
require.NoError(b.t, err)
|
||||
|
||||
// Tag the job so AcquireProvisionerJob only matches this
|
||||
// builder's job, preventing cross-test interference when
|
||||
// parallel tests share a database. Same pattern as
|
||||
// dbgen.ProvisionerJob.
|
||||
tags := database.StringMap{jobID.String(): "true", "scope": "organization"}
|
||||
|
||||
job, err := b.db.InsertProvisionerJob(ownerCtx, database.InsertProvisionerJobParams{
|
||||
ID: jobID,
|
||||
CreatedAt: takeFirstTime(b.jobCreatedAt, b.ws.CreatedAt, dbtime.Now()),
|
||||
@@ -383,7 +389,7 @@ func (b WorkspaceBuildBuilder) doInTX() WorkspaceResponse {
|
||||
FileID: uuid.New(),
|
||||
Type: database.ProvisionerJobTypeWorkspaceBuild,
|
||||
Input: payload,
|
||||
Tags: map[string]string{},
|
||||
Tags: tags,
|
||||
TraceMetadata: pqtype.NullRawMessage{},
|
||||
LogsOverflowed: false,
|
||||
})
|
||||
@@ -395,30 +401,24 @@ func (b WorkspaceBuildBuilder) doInTX() WorkspaceResponse {
|
||||
// Provisioner jobs are created in 'pending' status
|
||||
b.logger.Debug(context.Background(), "pending the provisioner job")
|
||||
case database.ProvisionerJobStatusRunning:
|
||||
// might need to do this multiple times if we got a template version
|
||||
// import job as well
|
||||
b.logger.Debug(context.Background(), "looping to acquire provisioner job")
|
||||
b.logger.Debug(context.Background(), "acquiring the provisioner job")
|
||||
startedAt := takeFirstTime(b.jobStartedAt, dbtime.Now())
|
||||
for {
|
||||
j, err := b.db.AcquireProvisionerJob(ownerCtx, database.AcquireProvisionerJobParams{
|
||||
OrganizationID: job.OrganizationID,
|
||||
StartedAt: sql.NullTime{
|
||||
Time: startedAt,
|
||||
Valid: true,
|
||||
},
|
||||
WorkerID: uuid.NullUUID{
|
||||
UUID: uuid.New(),
|
||||
Valid: true,
|
||||
},
|
||||
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
|
||||
ProvisionerTags: []byte(`{"scope": "organization"}`),
|
||||
})
|
||||
require.NoError(b.t, err, "acquire starting job")
|
||||
if j.ID == job.ID {
|
||||
b.logger.Debug(context.Background(), "acquired provisioner job", slog.F("job_id", job.ID))
|
||||
break
|
||||
}
|
||||
}
|
||||
j, err := b.db.AcquireProvisionerJob(ownerCtx, database.AcquireProvisionerJobParams{
|
||||
OrganizationID: job.OrganizationID,
|
||||
StartedAt: sql.NullTime{
|
||||
Time: startedAt,
|
||||
Valid: true,
|
||||
},
|
||||
WorkerID: uuid.NullUUID{
|
||||
UUID: uuid.New(),
|
||||
Valid: true,
|
||||
},
|
||||
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
|
||||
ProvisionerTags: must(json.Marshal(tags)),
|
||||
})
|
||||
require.NoError(b.t, err, "acquire the provisioner job")
|
||||
require.Equal(b.t, job.ID, j.ID, "acquired wrong provisioner job")
|
||||
b.logger.Debug(context.Background(), "acquired provisioner job", slog.F("job_id", job.ID))
|
||||
if !b.jobUpdatedAt.IsZero() {
|
||||
err = b.db.UpdateProvisionerJobByID(ownerCtx, database.UpdateProvisionerJobByIDParams{
|
||||
ID: job.ID,
|
||||
|
||||
Reference in New Issue
Block a user