Skip to content

Commit 82b3d55

Browse files
author
Newton Der
committed
Fix idle shutdown when active process is still running
1 parent ca83f64 commit 82b3d55

File tree

1 file changed

+80
-89
lines changed

1 file changed

+80
-89
lines changed

patches/sagemaker/sagemaker-idle-extension.diff

Lines changed: 80 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
Index: third-party-src/extensions/sagemaker-idle-extension/README.md
1+
Index: code-editor-src/extensions/sagemaker-idle-extension/README.md
22
===================================================================
33
--- /dev/null
4-
+++ third-party-src/extensions/sagemaker-idle-extension/README.md
4+
+++ code-editor-src/extensions/sagemaker-idle-extension/README.md
55
@@ -0,0 +1,3 @@
66
+# Code Editor Idle Extension
77
+
88
+The Code Editor Idle Extension tracks user activity and logs the last active timestamp (in UTC) to a local file. User activities monitored include file changes, text editor selection changes, and terminal interactions. Additionally, it provides an API endpoint `/api/idle` that returns the lastActiveTimestamp.
99
\ No newline at end of file
10-
Index: third-party-src/extensions/sagemaker-idle-extension/extension-browser.webpack.config.js
10+
Index: code-editor-src/extensions/sagemaker-idle-extension/extension-browser.webpack.config.js
1111
===================================================================
1212
--- /dev/null
13-
+++ third-party-src/extensions/sagemaker-idle-extension/extension-browser.webpack.config.js
13+
+++ code-editor-src/extensions/sagemaker-idle-extension/extension-browser.webpack.config.js
1414
@@ -0,0 +1,17 @@
1515
+/*---------------------------------------------------------------------------------------------
1616
+ * Copyright Amazon.com Inc. or its affiliates. All rights reserved.
@@ -29,10 +29,10 @@ Index: third-party-src/extensions/sagemaker-idle-extension/extension-browser.web
2929
+ extension: './src/extension.ts'
3030
+ },
3131
+});
32-
Index: third-party-src/extensions/sagemaker-idle-extension/extension.webpack.config.js
32+
Index: code-editor-src/extensions/sagemaker-idle-extension/extension.webpack.config.js
3333
===================================================================
3434
--- /dev/null
35-
+++ third-party-src/extensions/sagemaker-idle-extension/extension.webpack.config.js
35+
+++ code-editor-src/extensions/sagemaker-idle-extension/extension.webpack.config.js
3636
@@ -0,0 +1,20 @@
3737
+/*---------------------------------------------------------------------------------------------
3838
+ * Copyright Amazon.com Inc. or its affiliates. All rights reserved.
@@ -54,10 +54,10 @@ Index: third-party-src/extensions/sagemaker-idle-extension/extension.webpack.con
5454
+ extension: './src/extension.ts',
5555
+ }
5656
+});
57-
Index: third-party-src/extensions/sagemaker-idle-extension/package.json
57+
Index: code-editor-src/extensions/sagemaker-idle-extension/package.json
5858
===================================================================
5959
--- /dev/null
60-
+++ third-party-src/extensions/sagemaker-idle-extension/package.json
60+
+++ code-editor-src/extensions/sagemaker-idle-extension/package.json
6161
@@ -0,0 +1,43 @@
6262
+{
6363
+ "name": "sagemaker-idle-extension",
@@ -102,10 +102,10 @@ Index: third-party-src/extensions/sagemaker-idle-extension/package.json
102102
+ "dependencies": {},
103103
+ "repository": {}
104104
+}
105-
Index: third-party-src/extensions/sagemaker-idle-extension/tsconfig.json
105+
Index: code-editor-src/extensions/sagemaker-idle-extension/tsconfig.json
106106
===================================================================
107107
--- /dev/null
108-
+++ third-party-src/extensions/sagemaker-idle-extension/tsconfig.json
108+
+++ code-editor-src/extensions/sagemaker-idle-extension/tsconfig.json
109109
@@ -0,0 +1,10 @@
110110
+{
111111
+ "extends": "../tsconfig.base.json",
@@ -117,10 +117,10 @@ Index: third-party-src/extensions/sagemaker-idle-extension/tsconfig.json
117117
+ "../../src/vscode-dts/vscode.d.ts"
118118
+ ]
119119
+}
120-
Index: third-party-src/extensions/sagemaker-idle-extension/.vscodeignore
120+
Index: code-editor-src/extensions/sagemaker-idle-extension/.vscodeignore
121121
===================================================================
122122
--- /dev/null
123-
+++ third-party-src/extensions/sagemaker-idle-extension/.vscodeignore
123+
+++ code-editor-src/extensions/sagemaker-idle-extension/.vscodeignore
124124
@@ -0,0 +1,11 @@
125125
+.vscode/**
126126
+.vscode-test/**
@@ -133,42 +133,35 @@ Index: third-party-src/extensions/sagemaker-idle-extension/.vscodeignore
133133
+out/**
134134
+cgmanifest.json
135135
+preview-src/**
136-
Index: third-party-src/extensions/sagemaker-idle-extension/src/extension.ts
136+
Index: code-editor-src/extensions/sagemaker-idle-extension/src/extension.ts
137137
===================================================================
138138
--- /dev/null
139-
+++ third-party-src/extensions/sagemaker-idle-extension/src/extension.ts
140-
@@ -0,0 +1,112 @@
139+
+++ code-editor-src/extensions/sagemaker-idle-extension/src/extension.ts
140+
@@ -0,0 +1,59 @@
141141
+import * as vscode from "vscode";
142142
+import * as fs from "fs";
143143
+import * as path from "path";
144144
+
145-
+let idleFilePath: string
146-
+let terminalActivityInterval: NodeJS.Timeout | undefined
147-
+const LOG_PREFIX = "[sagemaker-idle-extension]"
148-
+const CHECK_INTERVAL = 60000; // 60 seconds interval
145+
+let idleFilePath: string;
149146
+
150147
+export function activate(context: vscode.ExtensionContext) {
151148
+ initializeIdleFilePath();
152149
+ registerEventListeners(context);
153150
+ startMonitoringTerminalActivity();
154151
+}
155152
+
156-
+export function deactivate() {
157-
+ if(terminalActivityInterval) {
158-
+ clearInterval(terminalActivityInterval)
159-
+ }
160-
+}
153+
+export function deactivate() {}
161154
+
162155
+/**
163156
+ * Initializes the file path where the idle timestamp will be stored.
164157
+ * It sets the path to a hidden file in the /tmp/ directory.
165158
+ */
166159
+function initializeIdleFilePath() {
167-
+ const tmpDirectory = "/tmp/";
160+
+ const tmpDirectory = "/tmp/";
168161
+ idleFilePath = path.join(tmpDirectory, ".sagemaker-last-active-timestamp");
169162
+
170163
+ // Set initial lastActivetimestamp
171-
+ updateLastActivityTimestamp()
164+
+ updateLastActivityTimestamp();
172165
+}
173166
+
174167
+/**
@@ -197,52 +190,6 @@ Index: third-party-src/extensions/sagemaker-idle-extension/src/extension.ts
197190
+}
198191
+
199192
+/**
200-
+ * Starts monitoring terminal activity by setting an interval to check for activity in the /dev/pts directory.
201-
+ */
202-
+const startMonitoringTerminalActivity = () => {
203-
+ terminalActivityInterval = setInterval(checkTerminalActivity, CHECK_INTERVAL);
204-
+};
205-
+
206-
+
207-
+/**
208-
+ * Checks for terminal activity by reading the /dev/pts directory and comparing modification times of the files.
209-
+ *
210-
+ * The /dev/pts directory is used in Unix-like operating systems to represent pseudo-terminal (PTY) devices.
211-
+ * Each active terminal session is assigned a PTY device. These devices are represented as files within the /dev/pts directory.
212-
+ * When a terminal session has activity, such as when a user inputs commands or output is written to the terminal,
213-
+ * the modification time (mtime) of the corresponding PTY device file is updated. By monitoring the modification
214-
+ * times of the files in the /dev/pts directory, we can detect terminal activity.
215-
+ *
216-
+ * If activity is detected (i.e., if any PTY device file was modified within the CHECK_INTERVAL), this function
217-
+ * updates the last activity timestamp.
218-
+ */
219-
+const checkTerminalActivity = () => {
220-
+ fs.readdir("/dev/pts", (err, files) => {
221-
+ if (err) {
222-
+ console.error(`${LOG_PREFIX} Error reading /dev/pts directory:`, err);
223-
+ return;
224-
+ }
225-
+
226-
+ const now = Date.now();
227-
+ const activityDetected = files.some((file) => {
228-
+ const filePath = path.join("/dev/pts", file);
229-
+ try {
230-
+ const stats = fs.statSync(filePath);
231-
+ const mtime = new Date(stats.mtime).getTime();
232-
+ return now - mtime < CHECK_INTERVAL;
233-
+ } catch (error) {
234-
+ console.error(`${LOG_PREFIX} Error reading file stats:`, error);
235-
+ return false;
236-
+ }
237-
+ });
238-
+
239-
+ if (activityDetected) {
240-
+ updateLastActivityTimestamp();
241-
+ }
242-
+ });
243-
+};
244-
+
245-
+/**
246193
+ * Updates the last activity timestamp by recording the current timestamp in the idle file and
247194
+ * refreshing the status bar. The timestamp should be in ISO 8601 format and set to the UTC timezone.
248195
+ */
@@ -251,10 +198,10 @@ Index: third-party-src/extensions/sagemaker-idle-extension/src/extension.ts
251198
+ fs.writeFileSync(idleFilePath, timestamp);
252199
+}
253200
\ No newline at end of file
254-
Index: third-party-src/build/gulpfile.extensions.js
201+
Index: code-editor-src/build/gulpfile.extensions.js
255202
===================================================================
256-
--- third-party-src.orig/build/gulpfile.extensions.js
257-
+++ third-party-src/build/gulpfile.extensions.js
203+
--- code-editor-src.orig/build/gulpfile.extensions.js
204+
+++ code-editor-src/build/gulpfile.extensions.js
258205
@@ -61,6 +61,7 @@ const compilations = [
259206
'extensions/search-result/tsconfig.json',
260207
'extensions/simple-browser/tsconfig.json',
@@ -263,10 +210,10 @@ Index: third-party-src/build/gulpfile.extensions.js
263210
'extensions/tunnel-forwarding/tsconfig.json',
264211
'extensions/typescript-language-features/test-workspace/tsconfig.json',
265212
'extensions/typescript-language-features/web/tsconfig.json',
266-
Index: third-party-src/build/npm/dirs.js
213+
Index: code-editor-src/build/npm/dirs.js
267214
===================================================================
268-
--- third-party-src.orig/build/npm/dirs.js
269-
+++ third-party-src/build/npm/dirs.js
215+
--- code-editor-src.orig/build/npm/dirs.js
216+
+++ code-editor-src/build/npm/dirs.js
270217
@@ -39,6 +39,7 @@ const dirs = [
271218
'extensions/php-language-features',
272219
'extensions/references-view',
@@ -275,28 +222,68 @@ Index: third-party-src/build/npm/dirs.js
275222
'extensions/search-result',
276223
'extensions/simple-browser',
277224
'extensions/tunnel-forwarding',
278-
Index: third-party-src/src/vs/server/node/webClientServer.ts
225+
Index: code-editor-src/src/vs/server/node/webClientServer.ts
279226
===================================================================
280-
--- third-party-src.orig/src/vs/server/node/webClientServer.ts
281-
+++ third-party-src/src/vs/server/node/webClientServer.ts
282-
@@ -3,7 +3,7 @@
227+
--- code-editor-src.orig/src/vs/server/node/webClientServer.ts
228+
+++ code-editor-src/src/vs/server/node/webClientServer.ts
229+
@@ -3,8 +3,9 @@
283230
* Licensed under the MIT License. See License.txt in the project root for license information.
284231
*--------------------------------------------------------------------------------------------*/
285232

286233
-import { createReadStream, promises } from 'fs';
287-
+import { createReadStream, promises, existsSync, writeFileSync } from 'fs';
234+
+import { createReadStream, promises, existsSync, readdirSync, statSync, writeFileSync } from 'fs';
288235
import * as http from 'http';
236+
+import * as path from 'path';
289237
import * as url from 'url';
290238
import * as cookie from 'cookie';
291-
@@ -96,6 +96,7 @@ const APP_ROOT = dirname(FileAccess.asFi
239+
import * as crypto from 'crypto';
240+
@@ -91,11 +92,45 @@ export async function serveFile(filePath
241+
}
242+
}
243+
244+
+const CHECK_INTERVAL = 60000; // 60 seconds interval
245+
const APP_ROOT = dirname(FileAccess.asFileUri('').fsPath);
246+
292247
const STATIC_PATH = `/static`;
293248
const CALLBACK_PATH = `/callback`;
294249
const WEB_EXTENSION_PATH = `/web-extension-resource`;
295250
+const IDLE_EXTENSION_PATH = `/api/idle`;
251+
+
252+
+/**
253+
+ * Checks for terminal activity by reading the /dev/pts directory and comparing modification times of the files.
254+
+ *
255+
+ * The /dev/pts directory is used in Unix-like operating systems to represent pseudo-terminal (PTY) devices.
256+
+ * Each active terminal session is assigned a PTY device. These devices are represented as files within the /dev/pts directory.
257+
+ * When a terminal session has activity, such as when a user inputs commands or output is written to the terminal,
258+
+ * the modification time (mtime) of the corresponding PTY device file is updated. By monitoring the modification
259+
+ * times of the files in the /dev/pts directory, we can detect terminal activity.
260+
+ *
261+
+ * If activity is detected (i.e., if any PTY device file was modified within the CHECK_INTERVAL), this function
262+
+ * updates the last activity timestamp.
263+
+ */
264+
+function checkTerminalActivity(idleFilePath: string) {
265+
+ try {
266+
+ const files: string[] = readdirSync('/dev/pts');
267+
+ const now = new Date();
268+
+
269+
+ const activityDetected = files.some((file: string) => {
270+
+ const filePath = path.join('/dev/pts', file);
271+
+ const stats = statSync(filePath);
272+
+ const mtime = new Date(stats.mtime).getTime();
273+
+ return now.getTime() - mtime < CHECK_INTERVAL;
274+
+ });
275+
+
276+
+ if (activityDetected) {
277+
+ writeFileSync(idleFilePath, now.toISOString());
278+
+ }
279+
+ } catch (err) {
280+
+ console.error('Error checking terminal activity:', err);
281+
+ }
282+
+}
296283

297284
export class WebClientServer {
298285

299-
@@ -133,6 +134,9 @@ export class WebClientServer {
286+
@@ -133,6 +168,9 @@ export class WebClientServer {
300287
// callback support
301288
return this._handleCallback(res);
302289
}
@@ -306,7 +293,7 @@ Index: third-party-src/src/vs/server/node/webClientServer.ts
306293
if (pathname.startsWith(WEB_EXTENSION_PATH) && pathname.charCodeAt(WEB_EXTENSION_PATH.length) === CharCode.Slash) {
307294
// extension resource support
308295
return this._handleWebExtensionResource(req, res, pathname.substring(WEB_EXTENSION_PATH.length));
309-
@@ -505,6 +509,31 @@ export class WebClientServer {
296+
@@ -505,6 +543,33 @@ export class WebClientServer {
310297
});
311298
return void res.end(data);
312299
}
@@ -318,16 +305,18 @@ Index: third-party-src/src/vs/server/node/webClientServer.ts
318305
+ try {
319306
+ const tmpDirectory = '/tmp/'
320307
+ const idleFilePath = join(tmpDirectory, '.sagemaker-last-active-timestamp');
321-
+
308+
+
322309
+ // If idle shutdown file does not exist, this indicates the app UI may never been opened
323310
+ // Create the initial metadata file
324311
+ if (!existsSync(idleFilePath)) {
325312
+ const timestamp = new Date().toISOString();
326313
+ writeFileSync(idleFilePath, timestamp);
327314
+ }
328-
+
315+
+
316+
+ checkTerminalActivity(idleFilePath);
317+
+
329318
+ const data = await promises.readFile(idleFilePath, 'utf8');
330-
+
319+
+
331320
+ res.statusCode = 200;
332321
+ res.setHeader('Content-Type', 'application/json');
333322
+ res.end(JSON.stringify({ lastActiveTimestamp: data }));
@@ -336,3 +325,5 @@ Index: third-party-src/src/vs/server/node/webClientServer.ts
336325
+ }
337326
+ }
338327
}
328+
329+

0 commit comments

Comments
 (0)