Skip to content

Commit b94aec1

Browse files
Integrate reading from log files into Supervisor's terminal.Listen (#19863)
* Integrate reading from log files into Supervisor's `terminal.Listen` * Try with GetOutput * do not bubble down and fail * remove debug stuff * definitions and impl of `task.proto` * codegen * update endpoint * Implement `ListenToOutput` * Try with one API (🤞) * stream beginning from where we left off * Do not watch closed tasks * move closing of worker channel * simplify one-off reading * codegen * consolidate for loops, optimize watching * remove extra line It makes sense to group the offset definition with the function below it * Gpl/ft/supervisor-listen-files (#19878) * commit step 1 * 2nd * Changes from joint code review --------- Co-authored-by: Filip Troníček <[email protected]> * Remove year bumps --------- Co-authored-by: Gero Posmyk-Leinemann <[email protected]>
1 parent 992e23b commit b94aec1

File tree

10 files changed

+2136
-13
lines changed

10 files changed

+2136
-13
lines changed

components/server/src/workspace/headless-log-service.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ import {
1515
TaskState,
1616
TaskStatus,
1717
} from "@gitpod/supervisor-api-grpcweb/lib/status_pb";
18-
import { ResponseStream, TerminalServiceClient } from "@gitpod/supervisor-api-grpcweb/lib/terminal_pb_service";
19-
import { ListenTerminalRequest, ListenTerminalResponse } from "@gitpod/supervisor-api-grpcweb/lib/terminal_pb";
18+
import { ResponseStream } from "@gitpod/supervisor-api-grpcweb/lib/terminal_pb_service";
19+
import { ListenToOutputRequest, ListenToOutputResponse } from "@gitpod/supervisor-api-grpcweb/lib/task_pb";
20+
import { TaskServiceClient } from "@gitpod/supervisor-api-grpcweb/lib/task_pb_service";
2021
import { WorkspaceInstance } from "@gitpod/gitpod-protocol";
2122
import * as grpc from "@grpc/grpc-js";
2223
import { Config } from "../config";
@@ -34,6 +35,7 @@ import {
3435
import { CachingHeadlessLogServiceClientProvider } from "../util/content-service-sugar";
3536
import { ctxIsAborted, ctxOnAbort } from "../util/request-context";
3637
import { PREBUILD_LOGS_PATH_PREFIX as PREBUILD_LOGS_PATH_PREFIX_common } from "@gitpod/public-api-common/lib/prebuild-utils";
38+
import { ApplicationError, ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error";
3739

3840
export const HEADLESS_LOGS_PATH_PREFIX = "/headless-logs";
3941
export const HEADLESS_LOG_DOWNLOAD_PATH_PREFIX = "/headless-log-download";
@@ -182,11 +184,7 @@ export class HeadlessLogService {
182184
// this might be the case when there is no terminal for this task, yet.
183185
// if we find any such case, we deem the workspace not ready yet, and try to reconnect later,
184186
// to be sure to get hold of all terminals created.
185-
throw new Error(`instance's ${instanceId} task ${task.getId()} has no terminal yet`);
186-
}
187-
if (task.getState() === TaskState.CLOSED) {
188-
// if a task has already been closed we can no longer access it's terminal, and have to skip it.
189-
continue;
187+
throw new Error(`instance's ${instanceId} task ${taskId} has no terminal yet`);
190188
}
191189
streams[taskId] = this.config.hostUrl
192190
.with({
@@ -276,21 +274,31 @@ export class HeadlessLogService {
276274
sink: (chunk: string) => Promise<void>,
277275
doContinue: () => Promise<boolean>,
278276
): Promise<void> {
279-
const client = new TerminalServiceClient(toSupervisorURL(logEndpoint.url), {
277+
const taskClient = new TaskServiceClient(toSupervisorURL(logEndpoint.url), {
280278
transport: WebsocketTransport(), // necessary because HTTPTransport causes caching issues
281279
});
282-
const req = new ListenTerminalRequest();
283-
req.setAlias(terminalID);
280+
281+
const tasks = await this.supervisorListTasks(logCtx, logEndpoint);
282+
const taskIndex = tasks.findIndex((t) => t.getTerminal() === terminalID);
283+
if (taskIndex < 0) {
284+
log.warn(logCtx, "stream workspace logs: terminal not found", { terminalID, tasks });
285+
throw new ApplicationError(ErrorCodes.NOT_FOUND, "terminal not found");
286+
}
287+
288+
const req = new ListenToOutputRequest();
289+
req.setTaskId(taskIndex.toString());
290+
291+
const authHeaders = HeadlessLogEndpoint.authHeaders(logCtx, logEndpoint);
284292

285293
let receivedDataYet = false;
286-
let stream: ResponseStream<ListenTerminalResponse> | undefined = undefined;
294+
let stream: ResponseStream<ListenToOutputResponse> | undefined = undefined;
287295
ctxOnAbort(() => stream?.cancel());
288296
const doStream = (retry: (doRetry?: boolean) => void) =>
289297
new Promise<void>((resolve, reject) => {
290298
// [gpl] this is the very reason we cannot redirect the frontend to the supervisor URL: currently we only have ownerTokens for authentication
291299
const decoder = new TextDecoder("utf-8");
292-
stream = client.listen(req, HeadlessLogEndpoint.authHeaders(logCtx, logEndpoint));
293-
stream.on("data", (resp: ListenTerminalResponse) => {
300+
stream = taskClient.listenToOutput(req, authHeaders);
301+
stream.on("data", (resp: ListenToOutputResponse) => {
294302
receivedDataYet = true;
295303

296304
const raw = resp.getData();

components/supervisor-api/go/task.pb.go

Lines changed: 227 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)