Skip to content

Commit fc11fbd

Browse files
committedMar 4, 2025·
Reworked Data Editor Heartbeat Structure
- Resolved continous logging of `getServerHeartbeat` requests - Extracted heartbeat functionality from DataEditorClient Closes #1021
1 parent 75e35ec commit fc11fbd

File tree

4 files changed

+97
-103
lines changed

4 files changed

+97
-103
lines changed
 

‎src/dataEditor/dataEditorClient.ts

+20-95
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import {
2525
createSimpleFileLogger,
2626
createViewport,
2727
del,
28-
destroySession,
2928
edit,
3029
EditorClient,
3130
endSessionTransaction,
@@ -38,11 +37,9 @@ import {
3837
getCounts,
3938
getLanguage,
4039
getLogger,
41-
getServerHeartbeat,
4240
getServerInfo,
4341
getViewportData,
4442
IOFlags,
45-
IServerInfo,
4643
modifyViewport,
4744
numAscii,
4845
profileSession,
@@ -77,17 +74,14 @@ import {
7774
MessageLevel,
7875
} from '../svelte/src/utilities/message'
7976
import * as editor_config from './config'
80-
import {
81-
HeartbeatInfo,
82-
IHeartbeatInfo,
83-
} from './include/server/heartbeat/HeartBeatInfo'
84-
import {
85-
configureOmegaEditPort,
86-
ServerInfo,
87-
ServerStopPredicate,
88-
} from './include/server/ServerInfo'
77+
import { configureOmegaEditPort, ServerInfo } from './include/server/ServerInfo'
8978
import { isDFDLDebugSessionActive } from './include/utils'
9079
import { SvelteWebviewInitializer } from './svelteWebviewInitializer'
80+
import {
81+
addActiveSession,
82+
removeActiveSession,
83+
} from './include/server/Sessions'
84+
import { getCurrentHeartbeatInfo } from './include/server/heartbeat'
9185

9286
// *****************************************************************************
9387
// global constants
@@ -108,13 +102,9 @@ const MAX_LOG_FILES: number = 5 // Maximum number of log files to keep TODO: mak
108102
// *****************************************************************************
109103
// file-scoped variables
110104
// *****************************************************************************
111-
112-
let activeSessions: string[] = []
105+
let serverInfo: ServerInfo = new ServerInfo()
113106
let checkpointPath: string = ''
114107
let client: EditorClient
115-
let getHeartbeatIntervalId: NodeJS.Timeout | number | undefined = undefined
116-
let heartbeatInfo: IHeartbeatInfo = new HeartbeatInfo()
117-
let serverInfo: IServerInfo = new ServerInfo()
118108
let omegaEditPort: number = 0
119109

120110
// *****************************************************************************
@@ -162,6 +152,7 @@ export class DataEditorClient implements vscode.Disposable {
162152
})
163153
this.panel.webview.onDidReceiveMessage(this.messageReceiver, this)
164154
this.panel.onDidDispose(async () => {
155+
await removeActiveSession(this.omegaSessionId)
165156
await this.dispose()
166157
})
167158
this.disposables.push(
@@ -187,20 +178,12 @@ export class DataEditorClient implements vscode.Disposable {
187178
addDisposable(dispoable: vscode.Disposable) {
188179
this.disposables.push(dispoable)
189180
}
190-
dispose(): void {
181+
async dispose(): Promise<void> {
191182
if (this.sendHeartbeatIntervalId) {
192183
clearInterval(this.sendHeartbeatIntervalId)
193184
this.sendHeartbeatIntervalId = undefined
194185
}
195186

196-
// destroy the session and remove it from the list of active sessions
197-
destroySession(this.omegaSessionId).then((id) => {
198-
removeActiveSession(id)
199-
serverStopIf(() => {
200-
return activeSessions.length == 0
201-
})
202-
})
203-
204187
for (let i = 0; i < this.disposables.length; i++)
205188
this.disposables[i].dispose()
206189
}
@@ -342,6 +325,8 @@ export class DataEditorClient implements vscode.Disposable {
342325
}
343326

344327
private async sendHeartbeat() {
328+
const heartbeatInfo = getCurrentHeartbeatInfo()
329+
345330
await this.panel.webview.postMessage({
346331
command: MessageCommand.heartbeat,
347332
data: {
@@ -353,13 +338,13 @@ export class DataEditorClient implements vscode.Disposable {
353338
sessionCount: heartbeatInfo.sessionCount,
354339
serverInfo: {
355340
omegaEditPort: this.configVars.port,
356-
serverVersion: heartbeatInfo.serverInfo.serverVersion,
357-
serverHostname: heartbeatInfo.serverInfo.serverHostname,
358-
serverProcessId: heartbeatInfo.serverInfo.serverProcessId,
359-
jvmVersion: heartbeatInfo.serverInfo.jvmVersion,
360-
jvmVendor: heartbeatInfo.serverInfo.jvmVendor,
361-
jvmPath: heartbeatInfo.serverInfo.jvmPath,
362-
availableProcessors: heartbeatInfo.serverInfo.availableProcessors,
341+
serverVersion: serverInfo.serverVersion,
342+
serverHostname: serverInfo.serverHostname,
343+
serverProcessId: serverInfo.serverProcessId,
344+
jvmVersion: serverInfo.jvmVersion,
345+
jvmVendor: serverInfo.jvmVendor,
346+
jvmPath: serverInfo.jvmPath,
347+
availableProcessors: serverInfo.availableProcessors,
363348
},
364349
},
365350
})
@@ -848,12 +833,6 @@ async function createDataEditorWebviewPanel(
848833
await checkServerListening(omegaEditPort, OMEGA_EDIT_HOST),
849834
'server not listening'
850835
)
851-
// initialize the first server heartbeat
852-
await getHeartbeat()
853-
assert(
854-
heartbeatInfo.serverInfo.serverVersion.length > 0,
855-
'heartbeat did not receive a server version'
856-
)
857836
}
858837
fileToEdit = fileToEdit.replace(
859838
editor_config.WorkspaceKeyword,
@@ -1132,9 +1111,7 @@ function removeDirectory(dirPath: string): void {
11321111
fs.rmdirSync(dirPath)
11331112
}
11341113
}
1135-
async function serverStopIf(predicate: ServerStopPredicate) {
1136-
if (predicate()) await serverStop()
1137-
}
1114+
11381115
async function serverStop() {
11391116
const serverPidFile = getPidFile(omegaEditPort)
11401117
if (fs.existsSync(serverPidFile)) {
@@ -1188,57 +1165,6 @@ function generateLogbackConfigFile(
11881165
return logbackConfigFile // Return the path to the logback config file
11891166
}
11901167

1191-
function addActiveSession(sessionId: string): void {
1192-
if (!activeSessions.includes(sessionId)) {
1193-
activeSessions.push(sessionId)
1194-
// scale the heartbeat interval based on the number of active sessions to reduce load on the server
1195-
getHeartbeat().then(() => {
1196-
if (getHeartbeatIntervalId) {
1197-
clearInterval(getHeartbeatIntervalId)
1198-
}
1199-
getHeartbeatIntervalId = setInterval(async () => {
1200-
await getHeartbeat()
1201-
}, HEARTBEAT_INTERVAL_MS * activeSessions.length)
1202-
})
1203-
}
1204-
}
1205-
1206-
function removeActiveSession(sessionId: string): void {
1207-
const index = activeSessions.indexOf(sessionId)
1208-
if (index >= 0) {
1209-
activeSessions.splice(index, 1)
1210-
clearInterval(getHeartbeatIntervalId)
1211-
getHeartbeatIntervalId = undefined
1212-
if (activeSessions.length > 0) {
1213-
// scale the heartbeat interval based on the number of active sessions
1214-
getHeartbeat().then(() => {
1215-
getHeartbeatIntervalId = setInterval(async () => {
1216-
await getHeartbeat()
1217-
}, HEARTBEAT_INTERVAL_MS * activeSessions.length)
1218-
})
1219-
}
1220-
}
1221-
}
1222-
1223-
async function getHeartbeat() {
1224-
assert(omegaEditPort > 0, `illegal Ωedit port ${omegaEditPort}`)
1225-
const heartbeat = await getServerHeartbeat(
1226-
activeSessions,
1227-
HEARTBEAT_INTERVAL_MS
1228-
)
1229-
heartbeatInfo.omegaEditPort = omegaEditPort
1230-
heartbeatInfo.latency = heartbeat.latency
1231-
heartbeatInfo.serverCommittedMemory = heartbeat.serverCommittedMemory
1232-
heartbeatInfo.serverCpuCount = heartbeat.serverCpuCount
1233-
heartbeatInfo.serverCpuLoadAverage = heartbeat.serverCpuLoadAverage
1234-
heartbeatInfo.serverMaxMemory = heartbeat.serverMaxMemory
1235-
heartbeatInfo.serverTimestamp = heartbeat.serverTimestamp
1236-
heartbeatInfo.serverUptime = heartbeat.serverUptime
1237-
heartbeatInfo.serverUsedMemory = heartbeat.serverUsedMemory
1238-
heartbeatInfo.sessionCount = heartbeat.sessionCount
1239-
heartbeatInfo.serverInfo = serverInfo
1240-
}
1241-
12421168
async function serverStart() {
12431169
await serverStop()
12441170
const serverStartingText = `Ωedit server starting on port ${omegaEditPort}`
@@ -1337,8 +1263,7 @@ async function serverStart() {
13371263
`Server version ${serverVersion} and client version ${clientVersion} must match`
13381264
)
13391265
}
1340-
// get an initial heartbeat
1341-
await getHeartbeat()
1266+
13421267
statusBarItem.text = `Ωedit server v${serverVersion} ready on port ${omegaEditPort} with PID ${serverInfo.serverProcessId}`
13431268
setTimeout(() => {
13441269
statusBarItem.dispose()
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
import { destroySession } from '@omega-edit/client'
18+
import { updateHeartbeatInterval } from './heartbeat'
19+
20+
let activeSessions: string[] = []
21+
22+
export function addActiveSession(sessionId: string): void {
23+
if (!activeSessions.includes(sessionId)) {
24+
activeSessions.push(sessionId)
25+
// scale the heartbeat interval based on the number of active sessions to reduce load on the server
26+
updateHeartbeatInterval(activeSessions)
27+
}
28+
}
29+
export async function removeActiveSession(sessionId: string) {
30+
const index = activeSessions.indexOf(sessionId)
31+
activeSessions.splice(index, 1)
32+
updateHeartbeatInterval(activeSessions)
33+
await destroySession(sessionId)
34+
}

‎src/dataEditor/include/server/heartbeat/HeartBeatInfo.ts

+2-8
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,9 @@
1414
* See the License for the specific language governing permissions and
1515
* limitations under the License.
1616
*/
17-
import { IServerHeartbeat, IServerInfo } from '@omega-edit/client'
18-
import { ServerInfo } from '../ServerInfo'
17+
import { IServerHeartbeat } from '@omega-edit/client'
1918

20-
export interface IHeartbeatInfo extends IServerHeartbeat {
21-
omegaEditPort: number // Ωedit server port
22-
serverInfo: IServerInfo // server info that remains constant
23-
}
24-
export class HeartbeatInfo {
19+
export class HeartbeatInfo implements IServerHeartbeat {
2520
omegaEditPort: number = 0 // Ωedit server port
2621
latency: number = 0 // latency in ms
2722
serverCommittedMemory: number = 0 // committed memory in bytes
@@ -32,5 +27,4 @@ export class HeartbeatInfo {
3227
serverUptime: number = 0 // uptime in ms
3328
serverUsedMemory: number = 0 // used memory in bytes
3429
sessionCount: number = 0 // session count
35-
serverInfo: IServerInfo = new ServerInfo()
3630
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
import { getServerHeartbeat, IServerHeartbeat } from '@omega-edit/client'
18+
import { HeartbeatInfo } from './HeartBeatInfo'
19+
20+
const HEARTBEAT_INTERVAL_MS: number = 1000 // 1 second (1000 ms)
21+
let heartbeatInfo: IServerHeartbeat = new HeartbeatInfo()
22+
let getHeartbeatIntervalId: NodeJS.Timeout | number | undefined = undefined
23+
24+
export function updateHeartbeatInterval(activeSessions: string[]) {
25+
if (getHeartbeatIntervalId) {
26+
clearInterval(getHeartbeatIntervalId)
27+
}
28+
getHeartbeatIntervalId =
29+
activeSessions.length > 0
30+
? setInterval(async () => {
31+
heartbeatInfo = await getServerHeartbeat(
32+
activeSessions,
33+
HEARTBEAT_INTERVAL_MS * activeSessions.length
34+
)
35+
})
36+
: undefined
37+
}
38+
39+
export function getCurrentHeartbeatInfo() {
40+
return heartbeatInfo
41+
}

0 commit comments

Comments
 (0)
Please sign in to comment.