(
accessToken: string,
partialRun: NewRun & {
taskSource: TaskSource
userId: string
batchConcurrencyLimit: number | null
},
branchArgs: BranchArgs,
)
| 56 | |
| 57 | @atimedMethod |
| 58 | async enqueueRun( |
| 59 | accessToken: string, |
| 60 | partialRun: NewRun & { |
| 61 | taskSource: TaskSource |
| 62 | userId: string |
| 63 | batchConcurrencyLimit: number | null |
| 64 | }, |
| 65 | branchArgs: BranchArgs, |
| 66 | ): Promise<RunId> { |
| 67 | const isProd = this.config.NODE_ENV === 'production' |
| 68 | const runId = isProd ? null : (random(1_000_000_000, 2_000_000_000) as RunId) |
| 69 | |
| 70 | let batchName: string | null = null |
| 71 | |
| 72 | const taskInfo = makeTaskInfo(this.config, partialRun.taskId, partialRun.taskSource, null) |
| 73 | const fetchedTask = await this.taskFetcher.fetch(taskInfo) |
| 74 | const taskVersion = getTaskVersion(taskInfo, fetchedTask) |
| 75 | |
| 76 | await this.dbRuns.transaction(async conn => { |
| 77 | if (partialRun.batchName != null) { |
| 78 | const existingBatchConcurrencyLimit = await this.dbRuns |
| 79 | .with(conn) |
| 80 | .getBatchConcurrencyLimit(partialRun.batchName) |
| 81 | if ( |
| 82 | existingBatchConcurrencyLimit != null && |
| 83 | existingBatchConcurrencyLimit !== partialRun.batchConcurrencyLimit |
| 84 | ) { |
| 85 | throw new TRPCError({ |
| 86 | code: 'BAD_REQUEST', |
| 87 | message: |
| 88 | `The batch ${partialRun.batchName} already exists and has a concurrency limit of ${existingBatchConcurrencyLimit}. ` + |
| 89 | `You must specify the same concurrency limit when creating new runs in this batch.`, |
| 90 | }) |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | batchName = partialRun.batchName ?? (await this.dbRuns.getDefaultBatchNameForUser(partialRun.userId)) |
| 95 | const batchConcurrencyLimit = partialRun.batchConcurrencyLimit ?? this.config.DEFAULT_RUN_BATCH_CONCURRENCY_LIMIT |
| 96 | |
| 97 | await this.dbRuns.with(conn).insertBatchInfo(batchName, batchConcurrencyLimit) |
| 98 | }) |
| 99 | |
| 100 | // We encrypt accessToken before storing it in the database. That way, an attacker with only |
| 101 | // database access can't use the access tokens stored there. If an attacker had access to both the database |
| 102 | // and the Vivaria server, they could decrypt the access tokens stored in the database, but they could also just |
| 103 | // change the web server processes to collect and store access tokens sent in API requests. |
| 104 | const { encrypted, nonce } = encrypt({ key: this.config.getAccessTokenSecretKey(), plaintext: accessToken }) |
| 105 | |
| 106 | return await this.dbRuns.insert( |
| 107 | runId, |
| 108 | { ...partialRun, batchName: batchName!, taskVersion }, |
| 109 | branchArgs, |
| 110 | this.config.VERSION ?? (await this.git.getServerCommitId()), |
| 111 | encrypted, |
| 112 | nonce, |
| 113 | partialRun.taskSource, |
| 114 | ) |
| 115 | } |
no test coverage detected