Skip to content

Commit 2f9e590

Browse files
committed
ensure no executions or child processes are being reused
1 parent 13370a1 commit 2f9e590

File tree

3 files changed

+44
-10
lines changed

3 files changed

+44
-10
lines changed

packages/cli-v3/src/entryPoints/managed/controller.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,17 @@ export class ManagedRunController {
178178
}
179179

180180
const execution = async () => {
181-
if (!this.currentExecution || !this.currentExecution.isPreparedForNextRun) {
181+
// If we have an existing execution that isn't prepared for the next run, kill it
182+
if (this.currentExecution && !this.currentExecution.canExecute) {
183+
this.sendDebugLog({
184+
runId: runFriendlyId,
185+
message: "killing existing execution before starting new run",
186+
});
187+
await this.currentExecution.kill().catch(() => {});
188+
this.currentExecution = null;
189+
}
190+
191+
if (!this.currentExecution || !this.currentExecution.canExecute) {
182192
this.currentExecution = new RunExecution({
183193
workerManifest: this.workerManifest,
184194
env: this.env,
@@ -267,11 +277,12 @@ export class ManagedRunController {
267277
if (this.currentExecution?.taskRunEnv) {
268278
this.sendDebugLog({
269279
runId: this.runFriendlyId,
270-
message: "waitForNextRun: eagerly recreating task run process",
280+
message: "waitForNextRun: eagerly creating fresh execution for next run",
271281
});
272282

273283
const previousTaskRunEnv = this.currentExecution.taskRunEnv;
274284

285+
// Create a fresh execution for the next run
275286
this.currentExecution = new RunExecution({
276287
workerManifest: this.workerManifest,
277288
env: this.env,

packages/cli-v3/src/entryPoints/managed/execution.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,6 @@ export class RunExecution {
8787
throw new Error("prepareForExecution called after process was already created");
8888
}
8989

90-
if (this.isPreparedForNextRun) {
91-
throw new Error("prepareForExecution called after execution was already prepared");
92-
}
93-
9490
this.taskRunProcess = this.createTaskRunProcess({
9591
envVars: opts.taskRunEnv,
9692
isWarmStart: true,
@@ -151,9 +147,14 @@ export class RunExecution {
151147
}
152148

153149
/**
154-
* Returns true if the execution has been prepared with task run env.
150+
* Returns true if no run has been started yet and the process is prepared for the next run.
155151
*/
156-
get isPreparedForNextRun(): boolean {
152+
get canExecute(): boolean {
153+
// If we've ever had a run ID, this execution can't be reused
154+
if (this._runFriendlyId) {
155+
return false;
156+
}
157+
157158
return !!this.taskRunProcess?.isPreparedForNextRun;
158159
}
159160

@@ -609,8 +610,18 @@ export class RunExecution {
609610
metrics: TaskRunExecutionMetrics;
610611
isWarmStart?: boolean;
611612
}) {
613+
// For immediate retries, we need to ensure the task run process is prepared for the next attempt
614+
if (
615+
this.runFriendlyId &&
616+
this.taskRunProcess &&
617+
!this.taskRunProcess.isPreparedForNextAttempt
618+
) {
619+
this.sendDebugLog("killing existing task run process before executing next attempt");
620+
await this.kill().catch(() => {});
621+
}
622+
612623
// To skip this step and eagerly create the task run process, run prepareForExecution first
613-
if (!this.taskRunProcess || !this.isPreparedForNextRun) {
624+
if (!this.taskRunProcess || !this.taskRunProcess.isPreparedForNextRun) {
614625
this.taskRunProcess = this.createTaskRunProcess({ envVars, isWarmStart });
615626
}
616627

@@ -667,11 +678,15 @@ export class RunExecution {
667678
}
668679

669680
public exit() {
670-
if (this.isPreparedForNextRun) {
681+
if (this.taskRunProcess?.isPreparedForNextRun) {
671682
this.taskRunProcess?.forceExit();
672683
}
673684
}
674685

686+
public async kill() {
687+
await this.taskRunProcess?.kill("SIGKILL");
688+
}
689+
675690
private async complete({ completion }: { completion: TaskRunExecutionResult }): Promise<void> {
676691
if (!this.runFriendlyId || !this.currentSnapshotId) {
677692
throw new Error("Cannot complete run: missing run or snapshot ID");

packages/cli-v3/src/executions/taskRunProcess.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,21 @@ export class TaskRunProcess {
8989
public onWait: Evt<OnWaitMessage> = new Evt();
9090

9191
private _isPreparedForNextRun: boolean = false;
92+
private _isPreparedForNextAttempt: boolean = false;
9293

9394
constructor(public readonly options: TaskRunProcessOptions) {
9495
this._isPreparedForNextRun = true;
96+
this._isPreparedForNextAttempt = true;
9597
}
9698

9799
get isPreparedForNextRun() {
98100
return this._isPreparedForNextRun;
99101
}
100102

103+
get isPreparedForNextAttempt() {
104+
return this._isPreparedForNextAttempt;
105+
}
106+
101107
async cancel() {
102108
this._isPreparedForNextRun = false;
103109
this._isBeingCancelled = true;
@@ -223,6 +229,7 @@ export class TaskRunProcess {
223229
isWarmStart?: boolean
224230
): Promise<TaskRunExecutionResult> {
225231
this._isPreparedForNextRun = false;
232+
this._isPreparedForNextAttempt = false;
226233

227234
let resolver: (value: TaskRunExecutionResult) => void;
228235
let rejecter: (err?: any) => void;
@@ -266,6 +273,7 @@ export class TaskRunProcess {
266273
const result = await promise;
267274

268275
this._currentExecution = undefined;
276+
this._isPreparedForNextAttempt = true;
269277

270278
return result;
271279
}

0 commit comments

Comments
 (0)