perf: do mapExecute() args sanity checks once
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Tue, 13 Aug 2024 18:22:44 +0000 (20:22 +0200)
committerJérôme Benoit <jerome.benoit@piment-noir.org>
Tue, 13 Aug 2024 18:22:44 +0000 (20:22 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
src/pools/abstract-pool.ts
tests/pools/abstract-pool.test.mjs

index 29dd42dbb7e7001bc127acc9202a2dea0a27a8b0..a45eef05ed191bda2f66889db0f4ea713b48541f 100644 (file)
@@ -1167,37 +1167,12 @@ export abstract class AbstractPool<
     )
   }
 
-  /** @inheritDoc */
-  public async execute (
+  private async internalExecute (
     data?: Data,
     name?: string,
     transferList?: readonly TransferListItem[]
   ): Promise<Response> {
     return await new Promise<Response>((resolve, reject) => {
-      if (!this.started) {
-        reject(new Error('Cannot execute a task on not started pool'))
-        return
-      }
-      if (this.destroying) {
-        reject(new Error('Cannot execute a task on destroying pool'))
-        return
-      }
-      if (name != null && typeof name !== 'string') {
-        reject(new TypeError('name argument must be a string'))
-        return
-      }
-      if (
-        name != null &&
-        typeof name === 'string' &&
-        name.trim().length === 0
-      ) {
-        reject(new TypeError('name argument must not be an empty string'))
-        return
-      }
-      if (transferList != null && !Array.isArray(transferList)) {
-        reject(new TypeError('transferList argument must be an array'))
-        return
-      }
       const timestamp = performance.now()
       const workerNodeKey = this.chooseWorkerNode(name)
       const task: Task<Data> = {
@@ -1237,11 +1212,41 @@ export abstract class AbstractPool<
   }
 
   /** @inheritDoc */
-  public mapExecute (
+  public async execute (
+    data?: Data,
+    name?: string,
+    transferList?: readonly TransferListItem[]
+  ): Promise<Response> {
+    if (!this.started) {
+      throw new Error('Cannot execute a task on not started pool')
+    }
+    if (this.destroying) {
+      throw new Error('Cannot execute a task on destroying pool')
+    }
+    if (name != null && typeof name !== 'string') {
+      throw new TypeError('name argument must be a string')
+    }
+    if (name != null && typeof name === 'string' && name.trim().length === 0) {
+      throw new TypeError('name argument must not be an empty string')
+    }
+    if (transferList != null && !Array.isArray(transferList)) {
+      throw new TypeError('transferList argument must be an array')
+    }
+    return await this.internalExecute(data, name, transferList)
+  }
+
+  /** @inheritDoc */
+  public async mapExecute (
     data: Iterable<Data>,
     name?: string,
     transferList?: readonly TransferListItem[]
   ): Promise<Response[]> {
+    if (!this.started) {
+      throw new Error('Cannot execute task(s) on not started pool')
+    }
+    if (this.destroying) {
+      throw new Error('Cannot execute task(s) on destroying pool')
+    }
     // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
     if (data == null) {
       throw new TypeError('data argument must be a defined iterable')
@@ -1249,11 +1254,22 @@ export abstract class AbstractPool<
     if (typeof data[Symbol.iterator] !== 'function') {
       throw new TypeError('data argument must be an iterable')
     }
+    if (name != null && typeof name !== 'string') {
+      throw new TypeError('name argument must be a string')
+    }
+    if (name != null && typeof name === 'string' && name.trim().length === 0) {
+      throw new TypeError('name argument must not be an empty string')
+    }
+    if (transferList != null && !Array.isArray(transferList)) {
+      throw new TypeError('transferList argument must be an array')
+    }
     if (!Array.isArray(data)) {
       data = [...data]
     }
-    return Promise.all(
-      (data as Data[]).map(data => this.execute(data, name, transferList))
+    return await Promise.all(
+      (data as Data[]).map(data =>
+        this.internalExecute(data, name, transferList)
+      )
     )
   }
 
index f8b983d41bda566cc60aed37a19acbb7f462561a..375d9653e7fed8e260c310479d62e34c52e185a3 100644 (file)
@@ -927,9 +927,6 @@ describe('Abstract pool test suite', () => {
     expect(pool.info.ready).toBe(false)
     expect(pool.workerNodes).toStrictEqual([])
     expect(pool.readyEventEmitted).toBe(false)
-    await expect(pool.execute()).rejects.toThrow(
-      new Error('Cannot execute a task on not started pool')
-    )
     pool.start()
     expect(pool.info.started).toBe(true)
     expect(pool.info.ready).toBe(true)
@@ -1767,12 +1764,24 @@ describe('Abstract pool test suite', () => {
       numberOfWorkers,
       './tests/worker-files/thread/testMultipleTaskFunctionsWorker.mjs'
     )
-    expect(() => pool.mapExecute()).toThrow(
+    await expect(pool.mapExecute()).rejects.toThrow(
       new TypeError('data argument must be a defined iterable')
     )
-    expect(() => pool.mapExecute(0)).toThrow(
+    await expect(pool.mapExecute(0)).rejects.toThrow(
       new TypeError('data argument must be an iterable')
     )
+    await expect(pool.mapExecute([undefined], 0)).rejects.toThrow(
+      new TypeError('name argument must be a string')
+    )
+    await expect(pool.mapExecute([undefined], '')).rejects.toThrow(
+      new TypeError('name argument must not be an empty string')
+    )
+    await expect(pool.mapExecute([undefined], undefined, {})).rejects.toThrow(
+      new TypeError('transferList argument must be an array')
+    )
+    await expect(pool.mapExecute([undefined], 'unknown')).rejects.toBe(
+      "Task function 'unknown' not found"
+    )
     let results = await pool.mapExecute([{}, {}, {}, {}])
     expect(results).toStrictEqual([{ ok: 1 }, { ok: 1 }, { ok: 1 }, { ok: 1 }])
     expect(pool.info.executingTasks).toBe(0)
@@ -1796,6 +1805,9 @@ describe('Abstract pool test suite', () => {
     expect(pool.info.executingTasks).toBe(0)
     expect(pool.info.executedTasks).toBe(12)
     await pool.destroy()
+    await expect(pool.mapExecute()).rejects.toThrow(
+      new Error('Cannot execute task(s) on not started pool')
+    )
   })
 
   it('Verify that task function objects worker is working', async () => {