diff --git a/components/dashboard/src/components/PrebuildLogs.tsx b/components/dashboard/src/components/PrebuildLogs.tsx
index e0b1530f04fbd3..7930a18f4e1d17 100644
--- a/components/dashboard/src/components/PrebuildLogs.tsx
+++ b/components/dashboard/src/components/PrebuildLogs.tsx
@@ -82,8 +82,10 @@ export default function PrebuildLogs(props: PrebuildLogsProps) {
useEffect(() => {
switch (workspaceInstance?.status.phase) {
// Preparing means that we haven't actually started the workspace instance just yet, but rather
- // are still preparing for launch. This means we're building the Docker image for the workspace.
+ // are still preparing for launch.
case "preparing":
+ // Building means we're building the Docker image for the workspace so the workspace hasn't started yet.
+ case "building":
case "stopped":
getGitpodService().server.watchWorkspaceImageBuildLogs(workspace!.id);
break;
diff --git a/components/dashboard/src/start/StartWorkspace.tsx b/components/dashboard/src/start/StartWorkspace.tsx
index 940517e530ae70..0bf31ccfda946b 100644
--- a/components/dashboard/src/start/StartWorkspace.tsx
+++ b/components/dashboard/src/start/StartWorkspace.tsx
@@ -340,7 +340,7 @@ export default class StartWorkspace extends React.Component;
// Pending means the workspace does not yet consume resources in the cluster, but rather is looking for
diff --git a/components/gitpod-protocol/src/gitpod-service.ts b/components/gitpod-protocol/src/gitpod-service.ts
index 5cf3454c8e1cbb..003744e21d53f8 100644
--- a/components/gitpod-protocol/src/gitpod-service.ts
+++ b/components/gitpod-protocol/src/gitpod-service.ts
@@ -530,13 +530,14 @@ const hasWindow = typeof window !== "undefined";
const phasesOrder: Record = {
unknown: 0,
preparing: 1,
- pending: 2,
- creating: 3,
- initializing: 4,
- running: 5,
- interrupted: 6,
- stopping: 7,
- stopped: 8,
+ building: 2,
+ pending: 3,
+ creating: 4,
+ initializing: 5,
+ running: 6,
+ interrupted: 7,
+ stopping: 8,
+ stopped: 9,
};
export class WorkspaceInstanceUpdateListener {
private readonly onDidChangeEmitter = new Emitter();
diff --git a/components/gitpod-protocol/src/workspace-instance.ts b/components/gitpod-protocol/src/workspace-instance.ts
index 3c06c0e22f2a0c..7992f656986f9a 100644
--- a/components/gitpod-protocol/src/workspace-instance.ts
+++ b/components/gitpod-protocol/src/workspace-instance.ts
@@ -98,9 +98,13 @@ export type WorkspaceInstancePhase =
| "unknown"
// Preparing means that we haven't actually started the workspace instance just yet, but rather
- // are still preparing for launch. This means we're building the Docker image for the workspace.
+ // are still preparing for launch.
| "preparing"
+ // Building means that we are building the Docker image for the workspace. A workspace will enter this phase only
+ // if an image build is required for that workspace.
+ | "building"
+
// Pending means the workspace does not yet consume resources in the cluster, but rather is looking for
// some space within the cluster. If for example the cluster needs to scale up to accomodate the
// workspace, the workspace will be in Pending state until that happened.
diff --git a/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodConnectionProvider.kt b/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodConnectionProvider.kt
index 063549b3f1c392..3c92e212a313a6 100644
--- a/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodConnectionProvider.kt
+++ b/components/ide/jetbrains/gateway-plugin/src/main/kotlin/io/gitpod/jetbrains/gateway/GitpodConnectionProvider.kt
@@ -164,6 +164,10 @@ class GitpodConnectionProvider : GatewayConnectionProvider {
when (update.status.phase) {
"preparing" -> {
phaseMessage.text = "Preparing"
+ statusMessage.text = "Preparing workspace..."
+ }
+ "building" -> {
+ phaseMessage.text = "Building"
statusMessage.text = "Building workspace image..."
}
"pending" -> {
diff --git a/components/server/src/workspace/gitpod-server-impl.ts b/components/server/src/workspace/gitpod-server-impl.ts
index c68c5f2fcc8e27..027495bb95e527 100644
--- a/components/server/src/workspace/gitpod-server-impl.ts
+++ b/components/server/src/workspace/gitpod-server-impl.ts
@@ -1541,8 +1541,8 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
await new Promise((resolve) => setTimeout(resolve, 2000));
const wsi = await this.workspaceDb.trace(ctx).findInstanceById(instance.id);
- if (!wsi || wsi.status.phase !== "preparing") {
- log.debug(logCtx, `imagebuild logs: instance is not/no longer in 'preparing' state`, {
+ if (!wsi || (wsi.status.phase !== "preparing" && wsi.status.phase !== "building")) {
+ log.debug(logCtx, `imagebuild logs: instance is not/no longer in 'building' state`, {
phase: wsi?.status.phase,
});
return;
diff --git a/components/server/src/workspace/headless-log-service.ts b/components/server/src/workspace/headless-log-service.ts
index 609ae62ba8df5d..fbd5b69d36cbd1 100644
--- a/components/server/src/workspace/headless-log-service.ts
+++ b/components/server/src/workspace/headless-log-service.ts
@@ -416,6 +416,7 @@ export class HeadlessLogService {
function isSupervisorAvailableSoon(wsi: WorkspaceInstance): boolean {
switch (wsi.status.phase) {
case "creating":
+ case "building":
case "preparing":
case "initializing":
case "pending":
diff --git a/components/ws-manager-bridge/src/bridge.ts b/components/ws-manager-bridge/src/bridge.ts
index a289b761da2008..da213e346942e0 100644
--- a/components/ws-manager-bridge/src/bridge.ts
+++ b/components/ws-manager-bridge/src/bridge.ts
@@ -106,7 +106,7 @@ export class WorkspaceManagerBridge implements Disposable {
// Still, listen to all updates, generate/derive new state and distribute it locally!
startStatusUpdateHandler(false);
- // emulate WorkspaceInstance updates for all Workspaces in the "preparing" phase in this cluster
+ // emulate WorkspaceInstance updates for all Workspaces in the "preparing" or "building" phase in this cluster
const updateEmulator = this.preparingUpdateEmulatorFactory() as PreparingUpdateEmulator;
this.disposables.push(updateEmulator);
updateEmulator.start(cluster.name);
diff --git a/components/ws-manager-bridge/src/preparing-update-emulator.ts b/components/ws-manager-bridge/src/preparing-update-emulator.ts
index e434d55ee29744..c4dda3ad14e0bd 100644
--- a/components/ws-manager-bridge/src/preparing-update-emulator.ts
+++ b/components/ws-manager-bridge/src/preparing-update-emulator.ts
@@ -42,7 +42,13 @@ export class PreparingUpdateEmulator implements Disposable {
const span = TraceContext.startSpan("preparingUpdateEmulatorRun");
const ctx = { span };
try {
- const instances = await this.workspaceDb.findInstancesByPhaseAndRegion("preparing", region);
+ const instances = (
+ await Promise.all([
+ this.workspaceDb.findInstancesByPhaseAndRegion("preparing", region),
+ this.workspaceDb.findInstancesByPhaseAndRegion("building", region),
+ ])
+ ).flat();
+
span.setTag("preparingUpdateEmulatorRun.nrOfInstances", instances.length);
for (const instance of instances) {
const hash = hasher(instance);