From eefab4ff5a24b6a5cd292c75d3dadd9705359833 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 3 Dec 2024 20:15:19 -0300 Subject: [PATCH 01/14] restart on error --- .../apps-engine/src/server/runtime/deno/LivenessManager.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts b/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts index 2450b3f2ad50..92c3e177fac3 100644 --- a/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts +++ b/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts @@ -155,6 +155,11 @@ export class LivenessManager { this.messenger.send(COMMAND_PING); } + private handleError(err: Error) { + this.debug('App has failed to start.`', err); + this.restartProcess(err.message); + } + private handleExit(exitCode: number, signal: string) { this.pingAbortController.emit('abort'); From c8debd943e0d53b6ac64fb540422952c65340805 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 3 Dec 2024 20:16:18 -0300 Subject: [PATCH 02/14] fix: potential memory leak on apps waitUntilReady --- .../runtime/deno/AppsEngineDenoRuntime.ts | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts b/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts index 458799286c83..b6c8a804aae3 100644 --- a/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts +++ b/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts @@ -318,18 +318,21 @@ export class DenoRuntimeSubprocessController extends EventEmitter { } private waitUntilReady(): Promise { + if (this.state === 'ready') { + return; + } return new Promise((resolve, reject) => { - const timeoutId = setTimeout(() => reject(new Error(`[${this.getAppId()}] Timeout: app process not ready`)), this.options.timeout); - - if (this.state === 'ready') { + let timeoutId: NodeJS.Timeout; + const handler = () => { clearTimeout(timeoutId); - return resolve(); - } + resolve(); + }; + timeoutId = setTimeout(() => { + this.off('ready', handler); + reject(new Error(`[${this.getAppId()}] Timeout: app process not ready`)); + }, this.options.timeout); - this.once('ready', () => { - clearTimeout(timeoutId); - return resolve(); - }); + this.once('ready', handler); }); } From 0c66e76a85fbb1e1d08b082644ac0930bb7de134 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 3 Dec 2024 20:30:09 -0300 Subject: [PATCH 03/14] .. --- packages/apps-engine/src/server/runtime/deno/LivenessManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts b/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts index 92c3e177fac3..9ca195b7b5b8 100644 --- a/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts +++ b/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts @@ -81,7 +81,7 @@ export class LivenessManager { this.pingTimeoutConsecutiveCount = 0; this.controller.once('ready', () => this.ping()); - this.subprocess.once('exit', this.handleExit.bind(this)); + this.subprocess.once('error', this.handleError.bind(this)); } /** From 6aca33d363030c2a78f0082f7ccc893f080ea9fe Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 3 Dec 2024 20:50:57 -0300 Subject: [PATCH 04/14] chore: increase delay to app restart in LivenessManager each retry --- packages/apps-engine/src/server/runtime/deno/LivenessManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts b/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts index 9ca195b7b5b8..cdd81bb4df09 100644 --- a/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts +++ b/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts @@ -199,6 +199,6 @@ export class LivenessManager { pid: this.subprocess.pid, }); - this.controller.restartApp(); + setTimeout(() => this.controller.restartApp(), Math.max(this.restartCount++ * 1000, 10 * 1000)); } } From 9a6337b53ab7489a65fae581647bd02f55657037 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Tue, 3 Dec 2024 21:06:16 -0300 Subject: [PATCH 05/14] .. --- packages/apps-engine/src/server/runtime/deno/LivenessManager.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts b/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts index cdd81bb4df09..d245d7ab09df 100644 --- a/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts +++ b/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts @@ -81,6 +81,7 @@ export class LivenessManager { this.pingTimeoutConsecutiveCount = 0; this.controller.once('ready', () => this.ping()); + this.subprocess.once('exit', this.handleExit.bind(this)); this.subprocess.once('error', this.handleError.bind(this)); } From f853ae6e2e5cf644e842ff07fee9e99dbe11a22f Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 4 Dec 2024 11:51:37 -0300 Subject: [PATCH 06/14] handle getStatus error --- .../deno-runtime/handlers/app/handler.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/apps-engine/deno-runtime/handlers/app/handler.ts b/packages/apps-engine/deno-runtime/handlers/app/handler.ts index 2a44f34cb7fe..0231ba21e5de 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/handler.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/handler.ts @@ -21,7 +21,23 @@ export default async function handleApp(method: string, params: unknown): Promis // We don't want the getStatus method to generate logs, so we handle it separately if (appMethod === 'getStatus') { - return handleGetStatus(); + try { + return handleGetStatus(); + } catch (e) { + if (!(e instanceof Error)) { + return new JsonRpcError('Unknown error', -32000, e); + } + + if ((e.cause as string)?.includes('invalid_param_type')) { + return JsonRpcError.invalidParams(null); + } + + if ((e.cause as string)?.includes('invalid_app')) { + return JsonRpcError.internalError({ message: 'App unavailable' }); + } + + return new JsonRpcError(e.message, -32000, e); + } } // `app` will be undefined if the method here is "app:construct" From cce2cefcf186a95c0b89cc13e1259b236eb2049e Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 4 Dec 2024 13:09:31 -0500 Subject: [PATCH 07/14] Update packages/apps-engine/deno-runtime/handlers/app/handler.ts --- packages/apps-engine/deno-runtime/handlers/app/handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/apps-engine/deno-runtime/handlers/app/handler.ts b/packages/apps-engine/deno-runtime/handlers/app/handler.ts index 0231ba21e5de..60420a2a6025 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/handler.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/handler.ts @@ -22,7 +22,7 @@ export default async function handleApp(method: string, params: unknown): Promis // We don't want the getStatus method to generate logs, so we handle it separately if (appMethod === 'getStatus') { try { - return handleGetStatus(); + return await handleGetStatus(); } catch (e) { if (!(e instanceof Error)) { return new JsonRpcError('Unknown error', -32000, e); From 7e4e32b50ef77336ffe31f31623b3a1c48dde274 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 5 Dec 2024 09:48:13 -0300 Subject: [PATCH 08/14] .. --- .../deno-runtime/handlers/app/handler.ts | 66 +++++++------------ 1 file changed, 25 insertions(+), 41 deletions(-) diff --git a/packages/apps-engine/deno-runtime/handlers/app/handler.ts b/packages/apps-engine/deno-runtime/handlers/app/handler.ts index 60420a2a6025..5ec4831561b0 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/handler.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/handler.ts @@ -20,56 +20,40 @@ export default async function handleApp(method: string, params: unknown): Promis const [, appMethod] = method.split(':'); // We don't want the getStatus method to generate logs, so we handle it separately - if (appMethod === 'getStatus') { - try { + try { + if (appMethod === 'getStatus') { return await handleGetStatus(); - } catch (e) { - if (!(e instanceof Error)) { - return new JsonRpcError('Unknown error', -32000, e); - } - - if ((e.cause as string)?.includes('invalid_param_type')) { - return JsonRpcError.invalidParams(null); - } - - if ((e.cause as string)?.includes('invalid_app')) { - return JsonRpcError.internalError({ message: 'App unavailable' }); - } - - return new JsonRpcError(e.message, -32000, e); } - } - // `app` will be undefined if the method here is "app:construct" - const app = AppObjectRegistry.get('app'); + // `app` will be undefined if the method here is "app:construct" + const app = AppObjectRegistry.get('app'); - app?.getLogger().debug(`'${appMethod}' is being called...`); + app?.getLogger().debug(`'${appMethod}' is being called...`); - if (uikitInteractions.includes(appMethod)) { - return handleUIKitInteraction(appMethod, params).then((result) => { - if (result instanceof JsonRpcError) { - app?.getLogger().debug(`'${appMethod}' was unsuccessful.`, result.message); - } else { - app?.getLogger().debug(`'${appMethod}' was successfully called! The result is:`, result); - } + if (uikitInteractions.includes(appMethod)) { + return handleUIKitInteraction(appMethod, params).then((result) => { + if (result instanceof JsonRpcError) { + app?.getLogger().debug(`'${appMethod}' was unsuccessful.`, result.message); + } else { + app?.getLogger().debug(`'${appMethod}' was successfully called! The result is:`, result); + } - return result; - }); - } + return result; + }); + } - if (appMethod.startsWith('check') || appMethod.startsWith('execute')) { - return handleListener(appMethod, params).then((result) => { - if (result instanceof JsonRpcError) { - app?.getLogger().debug(`'${appMethod}' was unsuccessful.`, result.message); - } else { - app?.getLogger().debug(`'${appMethod}' was successfully called! The result is:`, result); - } + if (appMethod.startsWith('check') || appMethod.startsWith('execute')) { + return handleListener(appMethod, params).then((result) => { + if (result instanceof JsonRpcError) { + app?.getLogger().debug(`'${appMethod}' was unsuccessful.`, result.message); + } else { + app?.getLogger().debug(`'${appMethod}' was successfully called! The result is:`, result); + } - return result; - }); - } + return result; + }); + } - try { let result: Defined | JsonRpcError; switch (appMethod) { From 5d8bcba77b05b5e9fa77d74000ecbd7d8500fc74 Mon Sep 17 00:00:00 2001 From: Douglas Gubert Date: Tue, 10 Dec 2024 15:17:38 -0300 Subject: [PATCH 09/14] .. --- .../deno-runtime/handlers/app/handler.ts | 2 +- .../runtime/deno/AppsEngineDenoRuntime.ts | 19 +++++++++---------- .../server/runtime/deno/ProcessMessenger.ts | 6 +++--- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/apps-engine/deno-runtime/handlers/app/handler.ts b/packages/apps-engine/deno-runtime/handlers/app/handler.ts index 5ec4831561b0..141e145df971 100644 --- a/packages/apps-engine/deno-runtime/handlers/app/handler.ts +++ b/packages/apps-engine/deno-runtime/handlers/app/handler.ts @@ -19,8 +19,8 @@ import handleOnUpdate from './handleOnUpdate.ts'; export default async function handleApp(method: string, params: unknown): Promise { const [, appMethod] = method.split(':'); - // We don't want the getStatus method to generate logs, so we handle it separately try { + // We don't want the getStatus method to generate logs, so we handle it separately if (appMethod === 'getStatus') { return await handleGetStatus(); } diff --git a/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts b/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts index b6c8a804aae3..bfd8ee4a99cc 100644 --- a/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts +++ b/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts @@ -5,18 +5,18 @@ import { type Readable, EventEmitter } from 'stream'; import debugFactory from 'debug'; import * as jsonrpc from 'jsonrpc-lite'; -import { LivenessManager } from './LivenessManager'; -import { ProcessMessenger } from './ProcessMessenger'; -import { bundleLegacyApp } from './bundler'; -import { decoder } from './codec'; import { AppStatus } from '../../../definition/AppStatus'; +import type { AppMethod } from '../../../definition/metadata'; import type { AppManager } from '../../AppManager'; import type { AppBridges } from '../../bridges'; import type { IParseAppPackageResult } from '../../compiler'; import { AppConsole, type ILoggerStorageEntry } from '../../logging'; import type { AppAccessorManager, AppApiManager } from '../../managers'; import type { AppLogStorage, IAppStorageItem } from '../../storage'; -import { AppMethod } from '../../../definition/metadata'; +import { LivenessManager } from './LivenessManager'; +import { ProcessMessenger } from './ProcessMessenger'; +import { bundleLegacyApp } from './bundler'; +import { decoder } from './codec'; const baseDebug = debugFactory('appsEngine:runtime:deno'); @@ -107,11 +107,7 @@ export class DenoRuntimeSubprocessController extends EventEmitter { private readonly livenessManager: LivenessManager; // We need to keep the appSource around in case the Deno process needs to be restarted - constructor( - manager: AppManager, - private readonly appPackage: IParseAppPackageResult, - private readonly storageItem: IAppStorageItem, - ) { + constructor(manager: AppManager, private readonly appPackage: IParseAppPackageResult, private readonly storageItem: IAppStorageItem) { super(); this.debug = baseDebug.extend(appPackage.info.id); @@ -321,12 +317,15 @@ export class DenoRuntimeSubprocessController extends EventEmitter { if (this.state === 'ready') { return; } + return new Promise((resolve, reject) => { let timeoutId: NodeJS.Timeout; + const handler = () => { clearTimeout(timeoutId); resolve(); }; + timeoutId = setTimeout(() => { this.off('ready', handler); reject(new Error(`[${this.getAppId()}] Timeout: app process not ready`)); diff --git a/packages/apps-engine/src/server/runtime/deno/ProcessMessenger.ts b/packages/apps-engine/src/server/runtime/deno/ProcessMessenger.ts index 03d03d125323..c919adb5f0bb 100644 --- a/packages/apps-engine/src/server/runtime/deno/ProcessMessenger.ts +++ b/packages/apps-engine/src/server/runtime/deno/ProcessMessenger.ts @@ -1,11 +1,11 @@ -import { ChildProcess } from 'child_process'; +import type { ChildProcess } from 'child_process'; import type { JsonRpc } from 'jsonrpc-lite'; import { encoder } from './codec'; export class ProcessMessenger { - private deno: ChildProcess; + private deno: ChildProcess | undefined; private _sendStrategy: (message: JsonRpc) => void; @@ -30,7 +30,7 @@ export class ProcessMessenger { } private switchStrategy() { - if (this.deno instanceof ChildProcess) { + if (this.deno?.stdin?.writable) { this._sendStrategy = this.strategySend.bind(this); } else { this._sendStrategy = this.strategyError.bind(this); From 35520197c23736dda10dd4b750b494d34dc35f7b Mon Sep 17 00:00:00 2001 From: Douglas Gubert Date: Mon, 16 Dec 2024 13:47:01 -0300 Subject: [PATCH 10/14] Error object doesn't serialize to JSON properly --- .../src/server/runtime/deno/AppsEngineDenoRuntime.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts b/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts index bfd8ee4a99cc..ef04da3c9fe7 100644 --- a/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts +++ b/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts @@ -287,7 +287,7 @@ export class DenoRuntimeSubprocessController extends EventEmitter { logger.info('Successfully restarted app subprocess'); } catch (e) { - logger.error("Failed to restart app's subprocess", { error: e }); + logger.error("Failed to restart app's subprocess", { error: e.message || e }); } finally { await this.logStorage.storeEntries(AppConsole.toStorageEntry(this.getAppId(), logger)); } From 6322eb0adc3afd1dba8eb057bac7cbc2a66554ac Mon Sep 17 00:00:00 2001 From: Douglas Gubert Date: Mon, 16 Dec 2024 15:53:00 -0300 Subject: [PATCH 11/14] Remove setTimeout on restart call --- packages/apps-engine/src/server/runtime/deno/LivenessManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts b/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts index d245d7ab09df..a852d16aec27 100644 --- a/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts +++ b/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts @@ -200,6 +200,6 @@ export class LivenessManager { pid: this.subprocess.pid, }); - setTimeout(() => this.controller.restartApp(), Math.max(this.restartCount++ * 1000, 10 * 1000)); + this.controller.restartApp(); } } From b6ed2ad88f67af949aa4aee6d251cc00e2e41d87 Mon Sep 17 00:00:00 2001 From: Douglas Gubert Date: Mon, 16 Dec 2024 16:00:08 -0300 Subject: [PATCH 12/14] Change ping timeout and restart count only after the restart --- .../src/server/runtime/deno/LivenessManager.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts b/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts index a852d16aec27..b4c8dfb5d520 100644 --- a/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts +++ b/packages/apps-engine/src/server/runtime/deno/LivenessManager.ts @@ -184,15 +184,13 @@ export class LivenessManager { this.restartProcess(reason); } - private restartProcess(reason: string) { + private async restartProcess(reason: string) { if (this.restartCount >= this.options.maxRestarts) { this.debug('Limit of restarts reached (%d). Aborting restart...', this.options.maxRestarts); this.controller.stopApp(); return; } - this.pingTimeoutConsecutiveCount = 0; - this.restartCount++; this.restartLog.push({ reason, restartedAt: new Date(), @@ -200,6 +198,9 @@ export class LivenessManager { pid: this.subprocess.pid, }); - this.controller.restartApp(); + await this.controller.restartApp(); + + this.pingTimeoutConsecutiveCount = 0; + this.restartCount++; } } From c1052efa41617ab68e8f9f40ec242973d00e2391 Mon Sep 17 00:00:00 2001 From: Douglas Gubert Date: Mon, 16 Dec 2024 19:20:11 -0300 Subject: [PATCH 13/14] Simple metrics collector --- .../apps-engine/deno-runtime/lib/messenger.ts | 4 ++++ .../deno-runtime/lib/metricsCollector.ts | 20 +++++++++++++++++ packages/apps-engine/deno-runtime/main.ts | 3 +++ .../runtime/deno/AppsEngineDenoRuntime.ts | 22 ++++++++++++++----- 4 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 packages/apps-engine/deno-runtime/lib/metricsCollector.ts diff --git a/packages/apps-engine/deno-runtime/lib/messenger.ts b/packages/apps-engine/deno-runtime/lib/messenger.ts index 1e9ffe05c6c5..5881d408c01c 100644 --- a/packages/apps-engine/deno-runtime/lib/messenger.ts +++ b/packages/apps-engine/deno-runtime/lib/messenger.ts @@ -59,6 +59,10 @@ export const Queue = new (class Queue { this.queue.push(encoder.encode(message)); this.processQueue(); } + + public getCurrentSize() { + return this.queue.length; + } }); export const Transport = new (class Transporter { diff --git a/packages/apps-engine/deno-runtime/lib/metricsCollector.ts b/packages/apps-engine/deno-runtime/lib/metricsCollector.ts new file mode 100644 index 000000000000..c257b6c8a35b --- /dev/null +++ b/packages/apps-engine/deno-runtime/lib/metricsCollector.ts @@ -0,0 +1,20 @@ +import { writeAll } from "https://deno.land/std@0.216.0/io/write_all.ts"; +import { Queue } from "./messenger.ts"; + +export function collectMetrics() { + return { + queueSize: Queue.getCurrentSize(), + } +}; + +const encoder = new TextEncoder(); + +export async function sendMetrics() { + const metrics = collectMetrics(); + + await writeAll(Deno.stderr, encoder.encode(JSON.stringify(metrics))); +} + +export function startMetricsReport() { + setInterval(sendMetrics, 5000); +} diff --git a/packages/apps-engine/deno-runtime/main.ts b/packages/apps-engine/deno-runtime/main.ts index fa2822908954..3983c8d52407 100644 --- a/packages/apps-engine/deno-runtime/main.ts +++ b/packages/apps-engine/deno-runtime/main.ts @@ -22,6 +22,7 @@ import apiHandler from './handlers/api-handler.ts'; import handleApp from './handlers/app/handler.ts'; import handleScheduler from './handlers/scheduler-handler.ts'; import registerErrorListeners from './error-handlers.ts'; +import { startMetricsReport } from "./lib/metricsCollector.ts"; type Handlers = { app: typeof handleApp; @@ -130,3 +131,5 @@ async function main() { registerErrorListeners(); main(); + +startMetricsReport(); diff --git a/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts b/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts index 01d32ecdfc0b..983b0a9343d3 100644 --- a/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts +++ b/packages/apps-engine/src/server/runtime/deno/AppsEngineDenoRuntime.ts @@ -5,6 +5,10 @@ import { type Readable, EventEmitter } from 'stream'; import debugFactory from 'debug'; import * as jsonrpc from 'jsonrpc-lite'; +import { LivenessManager } from './LivenessManager'; +import { ProcessMessenger } from './ProcessMessenger'; +import { bundleLegacyApp } from './bundler'; +import { decoder } from './codec'; import { AppStatus, AppStatusUtils } from '../../../definition/AppStatus'; import type { AppMethod } from '../../../definition/metadata'; import type { AppManager } from '../../AppManager'; @@ -13,10 +17,6 @@ import type { IParseAppPackageResult } from '../../compiler'; import { AppConsole, type ILoggerStorageEntry } from '../../logging'; import type { AppAccessorManager, AppApiManager } from '../../managers'; import type { AppLogStorage, IAppStorageItem } from '../../storage'; -import { LivenessManager } from './LivenessManager'; -import { ProcessMessenger } from './ProcessMessenger'; -import { bundleLegacyApp } from './bundler'; -import { decoder } from './codec'; const baseDebug = debugFactory('appsEngine:runtime:deno'); @@ -107,7 +107,11 @@ export class DenoRuntimeSubprocessController extends EventEmitter { private readonly livenessManager: LivenessManager; // We need to keep the appSource around in case the Deno process needs to be restarted - constructor(manager: AppManager, private readonly appPackage: IParseAppPackageResult, private readonly storageItem: IAppStorageItem) { + constructor( + manager: AppManager, + private readonly appPackage: IParseAppPackageResult, + private readonly storageItem: IAppStorageItem, + ) { super(); this.debug = baseDebug.extend(appPackage.info.id); @@ -639,6 +643,12 @@ export class DenoRuntimeSubprocessController extends EventEmitter { } private async parseError(chunk: Buffer): Promise { - console.error('Subprocess stderr', chunk.toString()); + try { + const data = JSON.parse(chunk.toString()); + + this.debug('Metrics received from subprocess: %o', data); + } catch (e) { + console.error('Subprocess stderr', chunk.toString()); + } } } From 6b71abd524aced24dd67756da59b0f8923768086 Mon Sep 17 00:00:00 2001 From: Douglas Gubert Date: Mon, 16 Dec 2024 20:16:16 -0300 Subject: [PATCH 14/14] Add changeset --- .changeset/giant-nails-trade.md | 5 +++++ .changeset/honest-kings-allow.md | 5 +++++ .changeset/quiet-radios-fry.md | 5 +++++ .changeset/young-dots-cheat.md | 5 +++++ 4 files changed, 20 insertions(+) create mode 100644 .changeset/giant-nails-trade.md create mode 100644 .changeset/honest-kings-allow.md create mode 100644 .changeset/quiet-radios-fry.md create mode 100644 .changeset/young-dots-cheat.md diff --git a/.changeset/giant-nails-trade.md b/.changeset/giant-nails-trade.md new file mode 100644 index 000000000000..76e92e999247 --- /dev/null +++ b/.changeset/giant-nails-trade.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/apps-engine': patch +--- + +Adds simple app subprocess metrics report diff --git a/.changeset/honest-kings-allow.md b/.changeset/honest-kings-allow.md new file mode 100644 index 000000000000..7ab8d0abc1a8 --- /dev/null +++ b/.changeset/honest-kings-allow.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/apps-engine': patch +--- + +Attempts to restart an app subprocess if the spawn command fails diff --git a/.changeset/quiet-radios-fry.md b/.changeset/quiet-radios-fry.md new file mode 100644 index 000000000000..b3b7209cb041 --- /dev/null +++ b/.changeset/quiet-radios-fry.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/apps-engine': patch +--- + +Fixes an issue while collecting the error message from a failed restart attempt of an app subprocess diff --git a/.changeset/young-dots-cheat.md b/.changeset/young-dots-cheat.md new file mode 100644 index 000000000000..e8d3b6c5bff6 --- /dev/null +++ b/.changeset/young-dots-cheat.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/apps-engine': patch +--- + +Prevents app:getStatus requests from timing out in some cases