Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/ws-manager-bridge/src/prebuild-state-mapper.ts
2498 views
1
/**
2
* Copyright (c) 2022 Gitpod GmbH. All rights reserved.
3
* Licensed under the GNU Affero General Public License (AGPL).
4
* See License.AGPL.txt in the project root for license information.
5
*/
6
7
import { HeadlessWorkspaceEventType, PrebuiltWorkspace } from "@gitpod/gitpod-protocol";
8
import { Client as ExperimentsClient } from "@gitpod/gitpod-protocol/lib/experiments/types";
9
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
10
import { TrustedValue } from "@gitpod/gitpod-protocol/lib/util/scrubbing";
11
import { WorkspacePhase, WorkspaceStatus } from "@gitpod/ws-manager/lib";
12
import { inject, injectable } from "inversify";
13
14
export interface PrebuildUpdate {
15
type: HeadlessWorkspaceEventType;
16
update: Partial<PrebuiltWorkspace>;
17
}
18
19
@injectable()
20
export class PrebuildStateMapper {
21
constructor(
22
@inject(ExperimentsClient)
23
private readonly experimentsClient: ExperimentsClient,
24
) {}
25
async mapWorkspaceStatusToPrebuild(status: WorkspaceStatus.AsObject): Promise<PrebuildUpdate | undefined> {
26
const canUseStoppedPhase = await this.experimentsClient.getValueAsync(
27
"ws_manager_bridge_stopped_prebuild_statuses",
28
false,
29
{},
30
);
31
if (!canUseStoppedPhase) {
32
if (status.phase === WorkspacePhase.STOPPED) {
33
return undefined;
34
}
35
if (status.phase !== WorkspacePhase.STOPPING) {
36
if (status.phase !== WorkspacePhase.RUNNING) {
37
return {
38
type: HeadlessWorkspaceEventType.Started,
39
update: {
40
state: "queued",
41
},
42
};
43
}
44
return {
45
type: HeadlessWorkspaceEventType.Started,
46
update: {
47
state: "building",
48
},
49
};
50
}
51
} else {
52
if (status.phase !== WorkspacePhase.STOPPED) {
53
if (![WorkspacePhase.RUNNING, WorkspacePhase.STOPPING].includes(status.phase)) {
54
return {
55
type: HeadlessWorkspaceEventType.Started,
56
update: {
57
state: "queued",
58
},
59
};
60
}
61
return {
62
type: HeadlessWorkspaceEventType.Started,
63
update: {
64
state: "building",
65
},
66
};
67
}
68
}
69
70
if (status.conditions?.timeout) {
71
return {
72
type: HeadlessWorkspaceEventType.AbortedTimedOut,
73
update: {
74
state: "timeout",
75
error: status.conditions.timeout,
76
},
77
};
78
} else if (status.conditions?.failed) {
79
return {
80
type: HeadlessWorkspaceEventType.Failed,
81
update: {
82
state: "failed",
83
error: status.conditions.failed,
84
},
85
};
86
} else if (status.conditions?.stoppedByRequest) {
87
return {
88
type: HeadlessWorkspaceEventType.Aborted,
89
update: {
90
state: "aborted",
91
error: "Cancelled",
92
},
93
};
94
} else if (status.conditions?.headlessTaskFailed) {
95
const result: PrebuildUpdate = {
96
type: HeadlessWorkspaceEventType.FinishedButFailed,
97
update: {
98
state: "available",
99
snapshot: status.conditions.snapshot,
100
error: status.conditions.headlessTaskFailed,
101
},
102
};
103
return result;
104
} else if (status.conditions?.snapshot) {
105
return {
106
type: HeadlessWorkspaceEventType.FinishedSuccessfully,
107
update: {
108
state: "available",
109
snapshot: status.conditions.snapshot,
110
error: "",
111
},
112
};
113
} else if (!status.conditions?.snapshot) {
114
// STOPPING && no snapshot is an intermediate state that we are choosing to ignore.
115
return undefined;
116
}
117
118
log.error({ instanceId: status.id }, "unhandled prebuild status update", {
119
phase: status.phase,
120
conditions: new TrustedValue(status.conditions).value,
121
});
122
return undefined;
123
}
124
}
125
126