Skip to content

Commit 03459a1

Browse files
geroplroboquat
authored andcommitted
[dashboard] Start at most one workspace after prebuild finished
Under certain circumstances - if a workspace failure appeared before the ideURL got set - we would never leave the HeadlessLogView but start a new workspace over and over again. As we do not handle this error well, it would only get caught by timeouts (1h), leading to users being effectively blocked because they reached their parallel workspace limit
1 parent a00db91 commit 03459a1

File tree

3 files changed

+27
-10
lines changed

3 files changed

+27
-10
lines changed

components/dashboard/src/start/CreateWorkspace.tsx

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -336,19 +336,32 @@ function RunningPrebuildView(props: RunningPrebuildViewProps) {
336336
const logsEmitter = new EventEmitter();
337337
const service = getGitpodService();
338338
let pollTimeout: NodeJS.Timeout | undefined;
339+
let prebuildDoneTriggered: boolean = false;
339340

340341
useEffect(() => {
341-
const pollIsPrebuildDone = async () => {
342-
clearTimeout(pollTimeout!);
343-
const available = await service.server.isPrebuildDone(props.runningPrebuild.prebuildID);
344-
if (available) {
342+
const checkIsPrebuildDone = async (): Promise<boolean> => {
343+
if (prebuildDoneTriggered) {
344+
console.debug("prebuild done already triggered, doing nothing");
345+
return true;
346+
}
347+
348+
const done = await service.server.isPrebuildDone(props.runningPrebuild.prebuildID);
349+
if (done) {
350+
// note: this treats "done" as "available" which is not equivalent.
351+
// This works because the backend ignores prebuilds which are not "available", and happily starts a workspace as if there was no prebuild at all.
352+
prebuildDoneTriggered = true;
345353
props.onPrebuildSucceeded();
346-
return;
354+
return true;
347355
}
356+
return false;
357+
};
358+
const pollIsPrebuildDone = async () => {
359+
clearTimeout(pollTimeout!);
360+
await checkIsPrebuildDone();
348361
pollTimeout = setTimeout(pollIsPrebuildDone, 10000);
349362
};
350363

351-
const disposables = watchHeadlessLogs(service.server, props.runningPrebuild.instanceID, (chunk) => logsEmitter.emit('logs', chunk), pollIsPrebuildDone);
364+
const disposables = watchHeadlessLogs(service.server, props.runningPrebuild.instanceID, (chunk) => logsEmitter.emit('logs', chunk), checkIsPrebuildDone);
352365
return function cleanup() {
353366
clearTimeout(pollTimeout!);
354367
disposables.dispose();

components/dashboard/src/start/StartWorkspace.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ function HeadlessWorkspaceView(props: { instanceId: string }) {
346346

347347
useEffect(() => {
348348
const service = getGitpodService();
349-
const disposables = watchHeadlessLogs(service.server, props.instanceId, (chunk) => logsEmitter.emit('logs', chunk), () => {});
349+
const disposables = watchHeadlessLogs(service.server, props.instanceId, (chunk) => logsEmitter.emit('logs', chunk), async () => { return false; });
350350
return function cleanup() {
351351
disposables.dispose();
352352
};

components/dashboard/src/start/WorkspaceLogs.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,13 @@ export default class WorkspaceLogs extends React.Component<WorkspaceLogsProps, W
8787
}
8888
}
8989

90-
export function watchHeadlessLogs(server: GitpodServer, instanceId: string, onLog: (chunk: string) => void, checkIsDone: () => Promise<void> | void): DisposableCollection {
90+
export function watchHeadlessLogs(server: GitpodServer, instanceId: string, onLog: (chunk: string) => void, checkIsDone: () => Promise<boolean>): DisposableCollection {
9191
const disposables = new DisposableCollection();
9292

9393
const startWatchingLogs = async () => {
94-
await checkIsDone();
94+
if (await checkIsDone()) {
95+
return;
96+
}
9597

9698
const retry = async (reason: string, err?: Error) => {
9799
console.debug("re-trying headless-logs because: " + reason, err);
@@ -155,7 +157,9 @@ export function watchHeadlessLogs(server: GitpodServer, instanceId: string, onLo
155157
}
156158
reader.cancel()
157159

158-
await checkIsDone();
160+
if (await checkIsDone()) {
161+
return;
162+
}
159163
} catch(err) {
160164
reader?.cancel().catch(console.debug);
161165
await retry("error while listening to stream", err);

0 commit comments

Comments
 (0)