4
4
*--------------------------------------------------------------------------------------------*/
5
5
6
6
import { WorkspaceInfo } from '@gitpod/gitpod-protocol' ;
7
- import { Workspace , WorkspaceInstanceStatus_Phase } from '@gitpod/public-api/lib/gitpod/experimental/v1/workspaces_pb' ;
8
7
import * as vscode from 'vscode' ;
9
8
import { Disposable } from './common/dispose' ;
10
9
import { withServerApi } from './internalApi' ;
@@ -13,6 +12,7 @@ import { SSHConnectionParams } from './remote';
13
12
import { ISessionService } from './services/sessionService' ;
14
13
import { ILogService } from './services/logService' ;
15
14
import { RawTelemetryEventProperties } from './common/telemetry' ;
15
+ import { WorkspaceState } from './workspaceState' ;
16
16
17
17
const IDEHeartbeatTelemetryEvent = 'ide_heartbeat' ;
18
18
interface IDEHeartbeatTelemetryData extends RawTelemetryEventProperties {
@@ -23,7 +23,7 @@ interface IDEHeartbeatTelemetryData extends RawTelemetryEventProperties {
23
23
instanceId : string ;
24
24
gitpodHost : string ;
25
25
debugWorkspace : 'true' | 'false' ;
26
- delta ?: { [ key : string ] : number ; } ;
26
+ delta ?: { [ key : string ] : number } ;
27
27
}
28
28
29
29
export class HeartbeatManager extends Disposable {
@@ -39,17 +39,17 @@ export class HeartbeatManager extends Disposable {
39
39
private eventCounterMap = new Map < string , number > ( ) ;
40
40
41
41
private ideHeartbeatTelemetryHandle : NodeJS . Timer | undefined ;
42
- private ideHeartbeatData : Pick < IDEHeartbeatTelemetryData , " successfulCount" | " totalCount" > = {
42
+ private ideHeartbeatData : Pick < IDEHeartbeatTelemetryData , ' successfulCount' | ' totalCount' > = {
43
43
successfulCount : 0 ,
44
44
totalCount : 0 ,
45
- }
45
+ } ;
46
46
47
47
constructor (
48
48
private readonly connectionInfo : SSHConnectionParams ,
49
+ private readonly workspaceState : WorkspaceState | undefined ,
49
50
private readonly sessionService : ISessionService ,
50
51
private readonly logService : ILogService ,
51
52
private readonly telemetryService : ITelemetryService ,
52
- private readonly usePublicApi : boolean ,
53
53
) {
54
54
super ( ) ;
55
55
this . _register ( vscode . window . onDidChangeActiveTextEditor ( e => this . updateLastActivity ( 'onDidChangeActiveTextEditor' , e ?. document ) ) ) ;
@@ -123,6 +123,15 @@ export class HeartbeatManager extends Disposable {
123
123
} , HeartbeatManager . HEARTBEAT_INTERVAL ) ;
124
124
125
125
this . ideHeartbeatTelemetryHandle = setInterval ( ( ) => this . sendIDEHeartbeatTelemetry ( ) , HeartbeatManager . IDE_HEARTBEAT_INTERVAL ) ;
126
+
127
+ if ( this . workspaceState ) {
128
+ this . _register ( this . workspaceState . onWorkspaceStopped ( ( ) => {
129
+ this . logService . trace ( 'Stopping heartbeat as workspace is not running' ) ;
130
+ this . stopHeartbeat ( ) ;
131
+ this . stopIDEHeartbeatTelemetry ( ) ;
132
+ this . sendIDEHeartbeatTelemetry ( ) ;
133
+ } ) ) ;
134
+ }
126
135
}
127
136
128
137
private updateLastActivity ( event : string , document ?: vscode . TextDocument ) {
@@ -136,39 +145,48 @@ export class HeartbeatManager extends Disposable {
136
145
}
137
146
138
147
private async sendHeartBeat ( wasClosed ?: true ) {
139
- let heartbeatSucceed = false
148
+ let heartbeatSucceed = false ;
140
149
try {
141
- await withServerApi ( this . sessionService . getGitpodToken ( ) , this . connectionInfo . gitpodHost , async service => {
142
- const workspaceInfo = this . usePublicApi
143
- ? await this . sessionService . getAPI ( ) . getWorkspace ( this . connectionInfo . workspaceId )
144
- : await service . server . getWorkspace ( this . connectionInfo . workspaceId ) ;
145
- this . isWorkspaceRunning = this . usePublicApi
146
- ? ( workspaceInfo as Workspace ) ?. status ?. instance ?. status ?. phase === WorkspaceInstanceStatus_Phase . RUNNING && ( workspaceInfo as Workspace ) ?. status ?. instance ?. instanceId === this . connectionInfo . instanceId
147
- : ( workspaceInfo as WorkspaceInfo ) . latestInstance ?. status ?. phase === 'running' && ( workspaceInfo as WorkspaceInfo ) . latestInstance ?. id === this . connectionInfo . instanceId ;
148
- if ( this . isWorkspaceRunning ) {
149
- this . usePublicApi
150
- ? ( ! wasClosed ? await this . sessionService . getAPI ( ) . sendHeartbeat ( this . connectionInfo . workspaceId ) : await this . sessionService . getAPI ( ) . sendDidClose ( this . connectionInfo . workspaceId ) )
151
- : await service . server . sendHeartBeat ( { instanceId : this . connectionInfo . instanceId , wasClosed } ) ;
152
- if ( wasClosed ) {
150
+ if ( this . workspaceState ) {
151
+ if ( this . workspaceState . isWorkspaceRunning ( ) ) {
152
+ if ( ! wasClosed ) {
153
+ await this . sessionService . getAPI ( ) . sendHeartbeat ( this . connectionInfo . workspaceId ) ;
154
+ this . logService . trace ( `Send heartbeat, triggered by ${ this . lastActivityEvent } event` ) ;
155
+ } else {
156
+ await this . sessionService . getAPI ( ) . sendDidClose ( this . connectionInfo . workspaceId ) ;
153
157
this . telemetryService . sendTelemetryEvent ( this . connectionInfo . gitpodHost , 'ide_close_signal' , { workspaceId : this . connectionInfo . workspaceId , instanceId : this . connectionInfo . instanceId , gitpodHost : this . connectionInfo . gitpodHost , clientKind : 'vscode' , debugWorkspace : String ( ! ! this . connectionInfo . debugWorkspace ) } ) ;
154
158
this . logService . trace ( `Send closed heartbeat` ) ;
155
- } else {
156
- this . logService . trace ( `Send heartbeat, triggered by ${ this . lastActivityEvent } event` ) ;
157
159
}
158
160
heartbeatSucceed = true ;
159
- } else {
160
- this . logService . trace ( 'Stopping heartbeat as workspace is not running' ) ;
161
- this . stopHeartbeat ( ) ;
162
- this . stopIDEHeartbeatTelemetry ( ) ;
163
161
}
164
- } , this . logService ) ;
162
+ } else {
163
+ await withServerApi ( this . sessionService . getGitpodToken ( ) , this . connectionInfo . gitpodHost , async service => {
164
+ const workspaceInfo = await service . server . getWorkspace ( this . connectionInfo . workspaceId ) ;
165
+ this . isWorkspaceRunning = workspaceInfo . latestInstance ?. status ?. phase === 'running' && ( workspaceInfo as WorkspaceInfo ) . latestInstance ?. id === this . connectionInfo . instanceId ;
166
+ if ( this . isWorkspaceRunning ) {
167
+ await service . server . sendHeartBeat ( { instanceId : this . connectionInfo . instanceId , wasClosed } ) ;
168
+ if ( wasClosed ) {
169
+ this . telemetryService . sendTelemetryEvent ( this . connectionInfo . gitpodHost , 'ide_close_signal' , { workspaceId : this . connectionInfo . workspaceId , instanceId : this . connectionInfo . instanceId , gitpodHost : this . connectionInfo . gitpodHost , clientKind : 'vscode' , debugWorkspace : String ( ! ! this . connectionInfo . debugWorkspace ) } ) ;
170
+ this . logService . trace ( `Send closed heartbeat` ) ;
171
+ } else {
172
+ this . logService . trace ( `Send heartbeat, triggered by ${ this . lastActivityEvent } event` ) ;
173
+ }
174
+ heartbeatSucceed = true ;
175
+ } else {
176
+ this . logService . trace ( 'Stopping heartbeat as workspace is not running' ) ;
177
+ this . stopHeartbeat ( ) ;
178
+ this . stopIDEHeartbeatTelemetry ( ) ;
179
+ this . sendIDEHeartbeatTelemetry ( ) ;
180
+ }
181
+ } , this . logService ) ;
182
+ }
165
183
} catch ( e ) {
166
184
const suffix = wasClosed ? 'closed heartbeat' : 'heartbeat' ;
167
185
const originMsg = e . message ;
168
186
e . message = `Failed to send ${ suffix } , triggered by event: ${ this . lastActivityEvent } : ${ originMsg } ` ;
169
187
this . logService . error ( e ) ;
170
188
e . message = `Failed to send ${ suffix } : ${ originMsg } ` ;
171
- this . telemetryService . sendTelemetryException ( this . connectionInfo . gitpodHost , e , { workspaceId : this . connectionInfo . workspaceId , instanceId : this . connectionInfo . instanceId } ) ;
189
+ this . telemetryService . sendTelemetryException ( this . connectionInfo . gitpodHost , e , { workspaceId : this . connectionInfo . workspaceId , instanceId : this . connectionInfo . instanceId } ) ;
172
190
} finally {
173
191
if ( heartbeatSucceed ) {
174
192
this . ideHeartbeatData . successfulCount ++ ;
@@ -184,6 +202,13 @@ export class HeartbeatManager extends Disposable {
184
202
}
185
203
}
186
204
205
+ private stopIDEHeartbeatTelemetry ( ) {
206
+ if ( this . ideHeartbeatTelemetryHandle ) {
207
+ clearInterval ( this . ideHeartbeatTelemetryHandle ) ;
208
+ this . ideHeartbeatTelemetryHandle = undefined ;
209
+ }
210
+ }
211
+
187
212
private sendIDEHeartbeatTelemetry ( ) {
188
213
this . telemetryService . sendRawTelemetryEvent ( this . connectionInfo . gitpodHost , IDEHeartbeatTelemetryEvent , {
189
214
...this . ideHeartbeatData ,
@@ -200,19 +225,12 @@ export class HeartbeatManager extends Disposable {
200
225
this . ideHeartbeatData . totalCount = 0 ;
201
226
}
202
227
203
- private stopIDEHeartbeatTelemetry ( ) {
204
- if ( this . ideHeartbeatTelemetryHandle ) {
205
- clearInterval ( this . ideHeartbeatTelemetryHandle ) ;
206
- this . ideHeartbeatTelemetryHandle = undefined ;
207
- this . sendIDEHeartbeatTelemetry ( )
208
- }
209
- }
210
-
211
228
public override async dispose ( ) : Promise < void > {
212
229
super . dispose ( ) ;
213
230
this . stopIDEHeartbeatTelemetry ( ) ;
214
231
this . stopHeartbeat ( ) ;
215
- if ( this . isWorkspaceRunning ) {
232
+ if ( this . workspaceState ?. isWorkspaceRunning ( ) ?? this . isWorkspaceRunning ) {
233
+ this . sendIDEHeartbeatTelemetry ( ) ;
216
234
await this . sendHeartBeat ( true ) ;
217
235
}
218
236
}
0 commit comments