Skip to content

Commit

Permalink
✨ Add commands for server stop and restart (konveyor#138)
Browse files Browse the repository at this point in the history
- New commands to be able to stop or restart (stop then start) the kai
  rpc server are now available via the command pallet

- The server start now waits for the process to be spawned (or in error)
  before continuing to setup the server

- Once running the server start will wait for either 5 seconds, or for
  the server to report it is ready. After that race, the server is
  considered started and ready to be initialized.

- Server status is changed to "stopped" when the spawned server process
  is fully closed.

---------

Signed-off-by: Scott J Dickerson <[email protected]>
  • Loading branch information
sjd78 authored Dec 6, 2024
1 parent 14895fd commit 162a12a
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 18 deletions.
12 changes: 12 additions & 0 deletions vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@
"category": "Konveyor",
"icon": "$(play)"
},
{
"command": "konveyor.stopServer",
"title": "Stop Server",
"category": "Konveyor",
"icon": "$(stop)"
},
{
"command": "konveyor.restartServer",
"title": "Restart Server",
"category": "Konveyor",
"icon": "$(restart)"
},
{
"command": "konveyor.runAnalysis",
"title": "Run Analysis",
Expand Down
59 changes: 43 additions & 16 deletions vscode/src/client/analyzerClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,19 +83,25 @@ export class AnalyzerClient {
this.outputChannel.appendLine(`server args:`);
this.getKaiRpcServerArgs().forEach((arg) => this.outputChannel.appendLine(` ${arg}`));

this.kaiRpcServer = spawn(this.getKaiRpcServerPath(), this.getKaiRpcServerArgs(), {
const kaiRpcServer = spawn(this.getKaiRpcServerPath(), this.getKaiRpcServerArgs(), {
cwd: serverCwd,
env: this.getKaiRpcServerEnv(),
});
this.kaiRpcServer = kaiRpcServer;

const pid = await new Promise<number | undefined>((resolve, reject) => {
kaiRpcServer.on("spawn", () => {
this.outputChannel.appendLine(
`kai rpc server has been spawned! [${this.kaiRpcServer?.pid}]`,
);
resolve(this.kaiRpcServer?.pid);
});

this.kaiRpcServer.on("spawn", () => {
this.outputChannel.appendLine(`kai rpc server has been spawned! [${this.kaiRpcServer?.pid}]`);
});

this.kaiRpcServer.on("error", (err) => {
this.outputChannel.appendLine(
`[error] - error in process[${this.kaiRpcServer?.spawnfile}]: ${err}`,
);
kaiRpcServer.on("error", (err) => {
const message = `error in process[${this.kaiRpcServer?.spawnfile}]: ${err}`;
this.outputChannel.appendLine(`[error] - ${message}}`);
reject();
});
});

this.kaiRpcServer.on("exit", (code, signal) => {
Expand All @@ -104,10 +110,18 @@ export class AnalyzerClient {

this.kaiRpcServer.on("close", (code, signal) => {
this.outputChannel.appendLine(`kai rpc server closed with signal ${signal}, code ${code}`);
this.fireStateChange("stopped");
});

let seenServerIsReady = false;
this.kaiRpcServer.stderr.on("data", (data) => {
this.outputChannel.appendLine(`${data.toString()}`);
const asString: string = data.toString();
this.outputChannel.appendLine(`${asString}`);

if (!seenServerIsReady && asString.match(/kai-rpc-logger .*Started kai RPC Server/)) {
seenServerIsReady = true;
this.kaiRpcServer?.emit("serverReportsReady", pid);
}
});

// Set up the JSON-RPC connection
Expand All @@ -117,19 +131,28 @@ export class AnalyzerClient {
);
this.rpcConnection.listen();

this.outputChannel.appendLine(`Started the kai rpc server, pid: ${this.kaiRpcServer.pid}`);
await Promise.race([
new Promise<void>((resolve) => {
kaiRpcServer.on("serverReportsReady", (pid) => {
this.outputChannel.appendLine(`*** kai rpc server [${pid}] reports ready`);
resolve();
});
}),
setTimeout(5000),
]);

this.outputChannel.appendLine(`Started the kai rpc server, pid: [${pid}]`);
}

// Stops the analyzer server
public stop(): void {
this.fireStateChange("stopping");
this.outputChannel.appendLine(`Stopping the kai rpc server ...`);
if (this.kaiRpcServer) {
if (this.kaiRpcServer && !this.kaiRpcServer.killed) {
this.kaiRpcServer.kill();
}
this.rpcConnection?.dispose();
this.kaiRpcServer = null;
this.fireStateChange("stopped");
this.outputChannel.appendLine(`kai rpc server stopped`);
}

Expand Down Expand Up @@ -206,7 +229,9 @@ export class AnalyzerClient {
"initialize",
initializeParams,
);
this.outputChannel.appendLine(`${response}`);
this.outputChannel.appendLine(
`'initialize' response: ${JSON.stringify(response, null, 2)}`,
);
progress.report({ message: "RPC Server initialized" });
this.fireStateChange("running");
return;
Expand Down Expand Up @@ -324,7 +349,8 @@ export class AnalyzerClient {
// Shutdown the server
public async shutdown(): Promise<void> {
try {
await this.rpcConnection!.sendRequest("shutdown", {});
this.outputChannel.appendLine(`Requesting kai rpc server shutdown...`);
await this.rpcConnection?.sendRequest("shutdown", {});
} catch (err: any) {
this.outputChannel.appendLine(`Error during shutdown: ${err.message}`);
vscode.window.showErrorMessage("Shutdown failed. See the output channel for details.");
Expand All @@ -334,7 +360,8 @@ export class AnalyzerClient {
// Exit the server
public async exit(): Promise<void> {
try {
await this.rpcConnection!.sendRequest("exit", {});
this.outputChannel.appendLine(`Requesting kai rpc server exit...`);
await this.rpcConnection?.sendRequest("exit", {});
} catch (err: any) {
this.outputChannel.appendLine(`Error during exit: ${err.message}`);
vscode.window.showErrorMessage("Exit failed. See the output channel for details.");
Expand Down
29 changes: 27 additions & 2 deletions vscode/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,37 @@ const commandsMap: (state: ExtensionState) => {
if (!(await analyzerClient.canAnalyzeInteractive())) {
return;
}

try {
await analyzerClient.start();
await analyzerClient.initialize();
} catch (e) {
console.error("Could not start the analyzer", e);
console.error("Could not start the server", e);
}
},
"konveyor.stopServer": async () => {
const analyzerClient = state.analyzerClient;
try {
await analyzerClient.shutdown();
await analyzerClient.stop();
} catch (e) {
console.error("Could not shutdown and stop the server", e);
}
},
"konveyor.restartServer": async () => {
const analyzerClient = state.analyzerClient;
try {
if (analyzerClient.isServerRunning()) {
await analyzerClient.shutdown();
await analyzerClient.stop();
}

if (!(await analyzerClient.canAnalyzeInteractive())) {
return;
}
await analyzerClient.start();
await analyzerClient.initialize();
} catch (e) {
console.error("Could not restart the server", e);
}
},
"konveyor.runAnalysis": async () => {
Expand Down

0 comments on commit 162a12a

Please sign in to comment.