From 5fd1e6bf528d56998a64e5238d4428af693b18c8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Thu, 24 Oct 2024 18:00:50 +0200 Subject: [PATCH] feat: add worker side error stack trace to WorkerError (#2631) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit * feat: add worker side error stack trace to WorkerError Signed-off-by: Jérôme Benoit * refactor: remove unneeded condition Signed-off-by: Jérôme Benoit --------- Signed-off-by: Jérôme Benoit --- src/utility-types.ts | 6 +++++- src/worker/abstract-worker.ts | 23 ++++++++++++----------- src/worker/thread-worker.ts | 2 +- tests/pools/cluster/fixed.test.mjs | 2 ++ tests/pools/thread/fixed.test.mjs | 2 ++ tests/worker/cluster-worker.test.mjs | 6 +++--- tests/worker/thread-worker.test.mjs | 6 +++--- 7 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/utility-types.ts b/src/utility-types.ts index 8ccb1a74..3c497457 100644 --- a/src/utility-types.ts +++ b/src/utility-types.ts @@ -21,7 +21,11 @@ export interface WorkerError { /** * Task function name triggering the error. */ - readonly name: string + readonly name?: string + /** + * Error stack trace. + */ + readonly stack?: string } /** diff --git a/src/worker/abstract-worker.ts b/src/worker/abstract-worker.ts index d49f37d8..3b63c454 100644 --- a/src/worker/abstract-worker.ts +++ b/src/worker/abstract-worker.ts @@ -87,8 +87,7 @@ export abstract class AbstractWorker< data, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion message: `Task function '${name!}' not found`, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - name: name!, + name, }, }) return @@ -127,9 +126,9 @@ export abstract class AbstractWorker< taskId, workerError: { data, - message: this.handleError(error as Error | string), - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - name: name!, + message: this.handleErrorMessage(error as Error | string), + name, + stack: (error as Error).stack, }, }) }) @@ -163,9 +162,9 @@ export abstract class AbstractWorker< taskId, workerError: { data, - message: this.handleError(error as Error | string), - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - name: name!, + message: this.handleErrorMessage(error as Error | string), + name, + stack: (error as Error).stack, }, }) } finally { @@ -220,11 +219,12 @@ export abstract class AbstractWorker< } /** - * Handles an error and convert it to a string so it can be sent back to the main worker. + * Handles an error and convert it if needed to its message string. + * Error are not structured-cloneable and cannot be sent to the main worker. * @param error - The error raised by the worker. * @returns The error message. */ - protected handleError (error: Error | string): string { + protected handleErrorMessage (error: Error | string): string { return error instanceof Error ? error.message : error } @@ -308,8 +308,9 @@ export abstract class AbstractWorker< ...(!status && error != null && { workerError: { - message: this.handleError(error as Error | string), + message: this.handleErrorMessage(error as Error | string), name: taskFunctionProperties.name, + stack: error.stack, }, }), }) diff --git a/src/worker/thread-worker.ts b/src/worker/thread-worker.ts index 82305d3f..f1f9602f 100644 --- a/src/worker/thread-worker.ts +++ b/src/worker/thread-worker.ts @@ -58,7 +58,7 @@ export class ThreadWorker< /** * @inheritDoc */ - protected override handleError (error: Error | string): string { + protected override handleErrorMessage (error: Error | string): string { return error as string } diff --git a/tests/pools/cluster/fixed.test.mjs b/tests/pools/cluster/fixed.test.mjs index 094e506d..493399b3 100644 --- a/tests/pools/cluster/fixed.test.mjs +++ b/tests/pools/cluster/fixed.test.mjs @@ -181,6 +181,7 @@ describe('Fixed cluster pool test suite', () => { data, message: 'Error Message from ClusterWorker', name: DEFAULT_TASK_NAME, + stack: expect.any(String), }) expect( errorPool.workerNodes.some( @@ -210,6 +211,7 @@ describe('Fixed cluster pool test suite', () => { data, message: 'Error Message from ClusterWorker:async', name: DEFAULT_TASK_NAME, + stack: expect.any(String), }) expect( asyncErrorPool.workerNodes.some( diff --git a/tests/pools/thread/fixed.test.mjs b/tests/pools/thread/fixed.test.mjs index 2ffc6c93..904d6a7f 100644 --- a/tests/pools/thread/fixed.test.mjs +++ b/tests/pools/thread/fixed.test.mjs @@ -208,6 +208,7 @@ describe('Fixed thread pool test suite', () => { data, message: new Error('Error Message from ThreadWorker'), name: DEFAULT_TASK_NAME, + stack: expect.any(String), }) expect( errorPool.workerNodes.some( @@ -240,6 +241,7 @@ describe('Fixed thread pool test suite', () => { data, message: new Error('Error Message from ThreadWorker:async'), name: DEFAULT_TASK_NAME, + stack: expect.any(String), }) expect( asyncErrorPool.workerNodes.some( diff --git a/tests/worker/cluster-worker.test.mjs b/tests/worker/cluster-worker.test.mjs index 732ba254..f76b0bfa 100644 --- a/tests/worker/cluster-worker.test.mjs +++ b/tests/worker/cluster-worker.test.mjs @@ -90,12 +90,12 @@ describe('Cluster worker test suite', () => { expect(worker.getMainWorker().send.calledOnce).toBe(true) }) - it('Verify that handleError() method is working properly', () => { + it('Verify that handleErrorMessage() method is working properly', () => { const error = new Error('Error as an error') const worker = new ClusterWorker(() => {}) - expect(worker.handleError(error)).toStrictEqual(error.message) + expect(worker.handleErrorMessage(error)).toStrictEqual(error.message) const errorMessage = 'Error as a string' - expect(worker.handleError(errorMessage)).toStrictEqual(errorMessage) + expect(worker.handleErrorMessage(errorMessage)).toStrictEqual(errorMessage) }) it('Verify that sendToMainWorker() method invokes the getMainWorker() and send() methods', () => { diff --git a/tests/worker/thread-worker.test.mjs b/tests/worker/thread-worker.test.mjs index 8f146b71..e3cd28da 100644 --- a/tests/worker/thread-worker.test.mjs +++ b/tests/worker/thread-worker.test.mjs @@ -90,12 +90,12 @@ describe('Thread worker test suite', () => { expect(worker.port.postMessage.calledOnce).toBe(true) }) - it('Verify that handleError() method is working properly', () => { + it('Verify that handleErrorMessage() method is working properly', () => { const error = new Error('Error as an error') const worker = new ThreadWorker(() => {}) - expect(worker.handleError(error)).toStrictEqual(error) + expect(worker.handleErrorMessage(error)).toStrictEqual(error) const errorMessage = 'Error as a string' - expect(worker.handleError(errorMessage)).toStrictEqual(errorMessage) + expect(worker.handleErrorMessage(errorMessage)).toStrictEqual(errorMessage) }) it('Verify that sendToMainWorker() method invokes the port property postMessage() method', () => { -- 2.34.1