Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/agentHost/node/agentHostService.ts
13394 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Event } from '../../../base/common/event.js';
7
import { Disposable, toDisposable } from '../../../base/common/lifecycle.js';
8
import { ILogService, ILoggerService } from '../../log/common/log.js';
9
import { RemoteLoggerChannelClient } from '../../log/common/logIpc.js';
10
import { IAgentHostStarter } from '../common/agent.js';
11
import { AgentHostIpcChannels } from '../common/agentService.js';
12
13
enum Constants {
14
MaxRestarts = 5,
15
}
16
17
/**
18
* Main-process service that manages the agent host utility process lifecycle
19
* (lazy start, crash recovery, logger forwarding). The renderer communicates
20
* with the utility process directly via MessagePort - this class does not
21
* relay any agent service calls.
22
*/
23
export class AgentHostProcessManager extends Disposable {
24
25
private _started = false;
26
private _wasQuitRequested = false;
27
private _restartCount = 0;
28
29
constructor(
30
private readonly _starter: IAgentHostStarter,
31
@ILogService private readonly _logService: ILogService,
32
@ILoggerService private readonly _loggerService: ILoggerService,
33
) {
34
super();
35
36
this._register(this._starter);
37
38
// Start lazily when the first window asks for a connection
39
if (this._starter.onRequestConnection) {
40
this._register(Event.once(this._starter.onRequestConnection)(() => this._ensureStarted()));
41
}
42
43
if (this._starter.onWillShutdown) {
44
this._register(this._starter.onWillShutdown(() => this._wasQuitRequested = true));
45
}
46
}
47
48
private _ensureStarted(): void {
49
if (!this._started) {
50
this._start();
51
}
52
}
53
54
private async _start(): Promise<void> {
55
this._started = true;
56
try {
57
const connection = await this._starter.start();
58
59
if (this._store.isDisposed) {
60
connection.store.dispose();
61
return;
62
}
63
64
this._logService.info('AgentHostProcessManager: agent host started');
65
66
// Connect logger channel so agent host logs appear in the output channel
67
this._register(new RemoteLoggerChannelClient(this._loggerService, connection.client.getChannel(AgentHostIpcChannels.Logger)));
68
69
// Handle unexpected exit
70
this._register(connection.onDidProcessExit(e => {
71
if (!this._wasQuitRequested && !this._store.isDisposed) {
72
if (this._restartCount <= Constants.MaxRestarts) {
73
this._logService.error(`AgentHostProcessManager: agent host terminated unexpectedly with code ${e.code}`);
74
this._restartCount++;
75
this._started = false;
76
connection.store.dispose();
77
this._start();
78
} else {
79
this._logService.error(`AgentHostProcessManager: agent host terminated with code ${e.code}, giving up after ${Constants.MaxRestarts} restarts`);
80
}
81
}
82
}));
83
84
this._register(toDisposable(() => connection.store.dispose()));
85
} catch (error) {
86
this._started = false;
87
this._logService.error('AgentHostProcessManager: failed to start agent host', error);
88
}
89
}
90
}
91
92