Skip to content

Commit

Permalink
[rebuild] fix 16535: auto manage windows (#16561)
Browse files Browse the repository at this point in the history
  • Loading branch information
akosyakov authored Feb 24, 2023
1 parent f0d1d1f commit ad26ca1
Show file tree
Hide file tree
Showing 9 changed files with 447 additions and 246 deletions.
27 changes: 8 additions & 19 deletions components/gitpod-cli/cmd/rebuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,9 @@ Connect using SSH keys (https://gitpod.io/keys):
%s
%s`, sep, workspaceUrl, ssh, sep)
err := notify(ctx, supervisorClient, workspaceUrl.String(), "The workspace is UP.")
err := openWindow(ctx, workspaceUrl.String())
if err != nil && ctx.Err() == nil {
log.WithError(err).Error("failed to notify")
log.WithError(err).Error("failed to open window")
}
}()

Expand Down Expand Up @@ -408,26 +408,15 @@ func setLoggerFormatter(logger *logrus.Logger) {
})
}

func notify(ctx context.Context, supervisorClient *supervisor.SupervisorClient, workspaceUrl, message string) error {
response, err := supervisorClient.Notification.Notify(ctx, &api.NotifyRequest{
Level: api.NotifyRequest_INFO,
Message: message,
Actions: []string{"Open"},
})
func openWindow(ctx context.Context, workspaceUrl string) error {
gpPath, err := exec.LookPath("gp")
if err != nil {
return err
}
if response.Action == "Open" {
gpPath, err := exec.LookPath("gp")
if err != nil {
return err
}
gpCmd := exec.CommandContext(ctx, gpPath, "preview", "--external", workspaceUrl)
gpCmd.Stdout = os.Stdout
gpCmd.Stderr = os.Stderr
return gpCmd.Run()
}
return nil
gpCmd := exec.CommandContext(ctx, gpPath, "preview", "--external", workspaceUrl)
gpCmd.Stdout = os.Stdout
gpCmd.Stderr = os.Stderr
return gpCmd.Run()
}

var rebuildOpts struct {
Expand Down
462 changes: 239 additions & 223 deletions components/supervisor-api/go/status.pb.go

Large diffs are not rendered by default.

121 changes: 121 additions & 0 deletions components/supervisor-api/go/status.pb.gw.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion components/supervisor-api/status.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ service StatusService {
rpc SupervisorStatus(SupervisorStatusRequest) returns (SupervisorStatusResponse) {
option (google.api.http) = {
get: "/v1/status/supervisor"
additional_bindings {
get: "/v1/status/supervisor/willShutdown/{willShutdown=true}",
}
};
}

Expand Down Expand Up @@ -81,7 +84,10 @@ service StatusService {

}

message SupervisorStatusRequest {}
message SupervisorStatusRequest {
// if true this request will return either when it times out or when the supervisor is about to shutdown.
bool willShutdown = 1;
}
message SupervisorStatusResponse {
bool ok = 1;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
ContentStatusResponse,
} from "@gitpod/supervisor-api-grpc/lib/status_pb";
import { WorkspaceInfoResponse } from "@gitpod/supervisor-api-grpc/lib/info_pb";

import { GitpodHostUrl } from "@gitpod/gitpod-protocol/lib/util/gitpod-host-url";

export class SupervisorServiceClient {
Expand All @@ -26,10 +25,46 @@ export class SupervisorServiceClient {
readonly ideReady = this.supervisorReady.then(() => this.checkReady("ide"));
readonly contentReady = Promise.all([this.supervisorReady]).then(() => this.checkReady("content"));
readonly getWorkspaceInfoPromise = this.supervisorReady.then(() => this.getWorkspaceInfo());
readonly supervisorWillShutdown = this.supervisorReady.then(() => this.checkWillShutdown());

private constructor() {}

private async checkReady(kind: "content" | "ide" | "supervisor", delay?: boolean): Promise<any> {
private async checkWillShutdown(delay = false): Promise<void> {
if (delay) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
try {
const wsSupervisorStatusUrl = GitpodHostUrl.fromWorkspaceUrl(window.location.href).with((url) => {
return {
pathname: "/_supervisor/v1/status/supervisor/willShutdown/true",
};
});
const response = await fetch(wsSupervisorStatusUrl.toString(), { credentials: "include" });
let result;
if (response.ok) {
result = await response.json();
if ((result as SupervisorStatusResponse.AsObject).ok) {
return;
}
}
if (response.status === 502) {
// bad gateway, supervisor is gone
return
}
console.debug(
`failed to check whether is about to shutdown, trying again...`,
response.status,
response.statusText,
JSON.stringify(result, undefined, 2),
);
} catch (e) {
// network errors
console.debug(`failed to check whether is about to shutdown, trying again...`, e);
}
await this.checkWillShutdown(true);
}

private async checkReady(kind: "content" | "ide" | "supervisor" , delay?: boolean): Promise<any> {
if (delay) {
await new Promise((resolve) => setTimeout(resolve, 1000));
}
Expand Down
10 changes: 10 additions & 0 deletions components/supervisor/frontend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import * as IDEWorker from "./ide/ide-worker";
import * as IDEWebSocket from "./ide/ide-web-socket";
import { SupervisorServiceClient } from "./ide/supervisor-service-client";
import * as LoadingFrame from "./shared/loading-frame";
import { workspaceUrl } from "./shared/urls";

window.gitpod = {} as any;
IDEWorker.install();
Expand Down Expand Up @@ -248,11 +249,15 @@ LoadingFrame.load().then(async (loading) => {
})();

(async () => {
const debugWorkspace = workspaceUrl.debugWorkspace;
//#region ide lifecycle
function isWorkspaceInstancePhase(phase: WorkspaceInstancePhase): boolean {
return frontendDashboardServiceClient.latestInfo?.statusPhase === phase;
}
if (!isWorkspaceInstancePhase("running")) {
if (debugWorkspace && frontendDashboardServiceClient.latestInfo) {
window.open('', '_self')?.close()
}
await new Promise<void>((resolve) => {
frontendDashboardServiceClient.onInfoUpdate((status) => {
if (status.statusPhase === "running") {
Expand All @@ -262,6 +267,11 @@ LoadingFrame.load().then(async (loading) => {
});
}
const supervisorServiceClient = SupervisorServiceClient.get();
if (debugWorkspace) {
supervisorServiceClient.supervisorWillShutdown.then(() => {
window.open('', '_self')?.close()
})
}
const [ideStatus] = await Promise.all([
supervisorServiceClient.ideReady,
supervisorServiceClient.contentReady,
Expand Down
17 changes: 16 additions & 1 deletion components/supervisor/pkg/supervisor/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ func (service *ideReadyState) Set(ready bool, info *DesktopIDEStatus) {
}

type statusService struct {
willShutdownCtx context.Context
ContentState ContentState
Ports *ports.Manager
Tasks *tasksManager
Expand All @@ -111,7 +112,21 @@ func (s *statusService) RegisterREST(mux *runtime.ServeMux, grpcEndpoint string)
return api.RegisterStatusServiceHandlerFromEndpoint(context.Background(), mux, grpcEndpoint, []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())})
}

func (s *statusService) SupervisorStatus(context.Context, *api.SupervisorStatusRequest) (*api.SupervisorStatusResponse, error) {
func (s *statusService) SupervisorStatus(ctx context.Context, req *api.SupervisorStatusRequest) (*api.SupervisorStatusResponse, error) {
if req.WillShutdown {
if s.willShutdownCtx.Err() != nil {
return &api.SupervisorStatusResponse{Ok: true}, nil
}
select {
case <-ctx.Done():
if errors.Is(ctx.Err(), context.Canceled) {
return nil, status.Error(codes.Canceled, "execution canceled")
}
return nil, status.Error(codes.DeadlineExceeded, ctx.Err().Error())
case <-s.willShutdownCtx.Done():
return &api.SupervisorStatusResponse{Ok: true}, nil
}
}
return &api.SupervisorStatusResponse{Ok: true}, nil
}

Expand Down
3 changes: 3 additions & 0 deletions components/supervisor/pkg/supervisor/supervisor.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,10 @@ func Run(options ...RunOption) {

taskManager := newTasksManager(cfg, termMuxSrv, cstate, nil, ideReady, desktopIdeReady)

willShutdownCtx, fireWillShutdown := context.WithCancel(ctx)
apiServices := []RegisterableService{
&statusService{
willShutdownCtx: willShutdownCtx,
ContentState: cstate,
Ports: portMgmt,
Tasks: taskManager,
Expand Down Expand Up @@ -459,6 +461,7 @@ func Run(options ...RunOption) {
}

log.Info("received SIGTERM (or shutdown) - tearing down")
fireWillShutdown()
terminalShutdownCtx, cancelTermination := context.WithTimeout(context.Background(), cfg.GetTerminationGracePeriod())
defer cancelTermination()
cancel()
Expand Down
6 changes: 6 additions & 0 deletions components/supervisor/validate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,10 @@ sudo rm -rf "/.supervisor/$COMPONENT" && true
sudo mv ./"$COMPONENT" /.supervisor
echo "$COMPONENT in /.supervisor replaced"

yarn --cwd "$DIR/frontend" run build

sudo rm -rf /.supervisor/frontend && true
sudo ln -s "$DIR/frontend/dist" /.supervisor/frontend
echo "$DIR/frontend/dist linked in /.supervisor/frontend"

gp rebuild --workspace-folder="$ROOT_DIR/dev/ide/example/workspace" --gitpod-env "GITPOD_ANALYTICS_SEGMENT_KEY=YErmvd89wPsrCuGcVnF2XAl846W9WIGl" "$@"

0 comments on commit ad26ca1

Please sign in to comment.