Skip to content

Commit dbb182a

Browse files
AlexTugarevroboquat
authored andcommitted
[server] mark prebuild as failed when image build fails
1 parent 13d0c09 commit dbb182a

File tree

3 files changed

+52
-27
lines changed

3 files changed

+52
-27
lines changed

components/server/ee/src/prebuilds/prebuild-manager.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,20 @@ export class PrebuildManager {
9797
}
9898
}
9999

100+
protected async findNonFailedPrebuiltWorkspace(ctx: TraceContext, cloneURL: string, commitSHA: string) {
101+
const existingPB = await this.workspaceDB.trace(ctx).findPrebuiltWorkspaceByCommit(cloneURL, commitSHA);
102+
103+
if (
104+
!!existingPB &&
105+
existingPB.state !== "aborted" &&
106+
existingPB.state !== "failed" &&
107+
existingPB.state !== "timeout"
108+
) {
109+
return existingPB;
110+
}
111+
return undefined;
112+
}
113+
100114
async startPrebuild(
101115
ctx: TraceContext,
102116
{ context, project, user, commitInfo }: StartPrebuildParams,
@@ -111,16 +125,10 @@ export class PrebuildManager {
111125
if (user.blocked) {
112126
throw new Error(`Blocked users cannot start prebuilds (${user.name})`);
113127
}
114-
const existingPB = await this.workspaceDB
115-
.trace({ span })
116-
.findPrebuiltWorkspaceByCommit(cloneURL, commitSHAIdentifier);
117-
// If the existing prebuild is failed, we want to retrigger it.
118-
if (
119-
!!existingPB &&
120-
existingPB.state !== "aborted" &&
121-
existingPB.state !== "failed" &&
122-
existingPB.state !== "timeout"
123-
) {
128+
const existingPB = await this.findNonFailedPrebuiltWorkspace({ span }, cloneURL, commitSHAIdentifier);
129+
130+
// If the existing prebuild is failed, it will be retriggered in the afterwards
131+
if (existingPB) {
124132
// If the existing prebuild is based on an outdated project config, we also want to retrigger it.
125133
const existingPBWS = await this.workspaceDB.trace({ span }).findById(existingPB.buildWorkspaceId);
126134
const existingConfig = existingPBWS?.config;

components/server/src/workspace/workspace-starter.ts

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ import {
5151
WorkspaceInstanceStatus,
5252
WorkspaceProbeContext,
5353
Permission,
54-
HeadlessWorkspaceEvent,
5554
HeadlessWorkspaceEventType,
5655
DisposableCollection,
5756
AdditionalContentContext,
@@ -718,28 +717,39 @@ export class WorkspaceStarter {
718717
await this.messageBus.notifyOnInstanceUpdate(workspace.ownerId, instance);
719718

720719
// If we just attempted to start a workspace for a prebuild - and that failed, we have to fail the prebuild itself.
720+
await this.failPrebuildWorkspace({ span }, err, workspace);
721+
} catch (err) {
722+
TraceContext.setError({ span }, err);
723+
log.error(
724+
{ workspaceId: workspace.id, instanceId: instance.id, userId: workspace.ownerId },
725+
"cannot properly fail workspace instance during start",
726+
err,
727+
);
728+
} finally {
729+
span.finish();
730+
}
731+
}
732+
733+
protected async failPrebuildWorkspace(ctx: TraceContext, err: Error, workspace: Workspace) {
734+
const span = TraceContext.startSpan("failInstanceStart", ctx);
735+
try {
721736
if (workspace.type === "prebuild") {
722737
const prebuild = await this.workspaceDb.trace({ span }).findPrebuildByWorkspaceID(workspace.id);
723738
if (prebuild && prebuild.state !== "failed") {
724739
prebuild.state = "failed";
725740
prebuild.error = err.toString();
726741

727742
await this.workspaceDb.trace({ span }).storePrebuiltWorkspace(prebuild);
728-
await this.messageBus.notifyHeadlessUpdate({ span }, workspace.ownerId, workspace.id, <
729-
HeadlessWorkspaceEvent
730-
>{
743+
await this.messageBus.notifyHeadlessUpdate({ span }, workspace.ownerId, workspace.id, {
731744
type: HeadlessWorkspaceEventType.Failed,
732-
// TODO: `workspaceID: workspace.id` not needed here? (found in ee/src/prebuilds/prebuild-queue-maintainer.ts and ee/src/bridge.ts)
745+
workspaceID: workspace.id, // required in prebuild-queue-maintainer.ts
746+
text: "",
733747
});
734748
}
735749
}
736750
} catch (err) {
737751
TraceContext.setError({ span }, err);
738-
log.error(
739-
{ workspaceId: workspace.id, instanceId: instance.id, userId: workspace.ownerId },
740-
"cannot properly fail workspace instance during start",
741-
err,
742-
);
752+
throw err;
743753
} finally {
744754
span.finish();
745755
}
@@ -1286,6 +1296,11 @@ export class WorkspaceStarter {
12861296
stoppedTime: now,
12871297
stoppingTime: now,
12881298
});
1299+
1300+
// Mark the PrebuildWorkspace as failed
1301+
await this.failPrebuildWorkspace({ span }, err, workspace);
1302+
1303+
// Push updated workspace instance over messagebus
12891304
await this.messageBus.notifyOnInstanceUpdate(workspace.ownerId, instance);
12901305

12911306
TraceContext.setError({ span }, err);
@@ -1419,14 +1434,16 @@ export class WorkspaceStarter {
14191434

14201435
if (workspace.config.coreDump?.enabled) {
14211436
// default core dump size is 262144 blocks (if blocksize is 4096)
1422-
const defaultLimit:number=1073741824;
1437+
const defaultLimit: number = 1073741824;
14231438

14241439
const rLimitCore = new EnvironmentVariable();
14251440
rLimitCore.setName("GITPOD_RLIMIT_CORE");
1426-
rLimitCore.setValue(JSON.stringify({
1427-
softLimit: workspace.config.coreDump?.softLimit || defaultLimit,
1428-
hardLimit: workspace.config.coreDump?.hardLimit || defaultLimit,
1429-
}));
1441+
rLimitCore.setValue(
1442+
JSON.stringify({
1443+
softLimit: workspace.config.coreDump?.softLimit || defaultLimit,
1444+
hardLimit: workspace.config.coreDump?.hardLimit || defaultLimit,
1445+
}),
1446+
);
14301447
envvars.push(rLimitCore);
14311448
}
14321449

components/ws-manager-bridge/ee/src/prebuild-updater-db.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import { inject, injectable } from "inversify";
88
import { TraceContext } from "@gitpod/gitpod-protocol/lib/util/tracing";
99
import { WorkspaceStatus, WorkspaceType } from "@gitpod/ws-manager/lib";
10-
import { HeadlessWorkspaceEvent } from "@gitpod/gitpod-protocol/lib/headless-workspace-log";
1110
import { WorkspaceInstance } from "@gitpod/gitpod-protocol";
1211
import { log, LogContext } from "@gitpod/gitpod-protocol/lib/util/logging";
1312
import { PrebuildStateMapper } from "../../src/prebuild-state-mapper";
@@ -98,9 +97,10 @@ export class PrebuildUpdaterDB implements PrebuildUpdater {
9897

9998
// notify updates
10099
// headless update
101-
await this.messagebus.notifyHeadlessUpdate({ span }, userId, workspaceId, <HeadlessWorkspaceEvent>{
100+
await this.messagebus.notifyHeadlessUpdate({ span }, userId, workspaceId, {
102101
type: update.type,
103102
workspaceID: workspaceId,
103+
text: "",
104104
});
105105

106106
// prebuild info

0 commit comments

Comments
 (0)