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