HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux ip-172-31-4-197 6.8.0-1036-aws #38~22.04.1-Ubuntu SMP Fri Aug 22 15:44:33 UTC 2025 x86_64
User: ubuntu (1000)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/web.enelar.com.co/node_modules/piscina/test/abort-task.ts
import { EventEmitter } from 'events';
import Piscina from '..';
import { test } from 'tap';
import { resolve } from 'path';

test('tasks can be aborted through AbortController while running', async ({ equal, rejects }) => {
  const pool = new Piscina({
    filename: resolve(__dirname, 'fixtures/notify-then-sleep.ts')
  });

  const buf = new Int32Array(new SharedArrayBuffer(4));
  const abortController = new AbortController();
  rejects(pool.runTask(buf, abortController.signal),
    /The task has been aborted/);

  Atomics.wait(buf, 0, 0);
  equal(Atomics.load(buf, 0), 1);

  abortController.abort();
});

test('tasks can be aborted through EventEmitter while running', async ({ equal, rejects }) => {
  const pool = new Piscina({
    filename: resolve(__dirname, 'fixtures/notify-then-sleep.ts')
  });

  const buf = new Int32Array(new SharedArrayBuffer(4));
  const ee = new EventEmitter();
  rejects(pool.runTask(buf, ee), /The task has been aborted/);
  rejects(pool.run(buf, { signal: ee }), /The task has been aborted/);

  Atomics.wait(buf, 0, 0);
  equal(Atomics.load(buf, 0), 1);

  ee.emit('abort');
});

test('tasks can be aborted through EventEmitter before running', async ({ equal, rejects }) => {
  const pool = new Piscina({
    filename: resolve(__dirname, 'fixtures/wait-for-notify.ts'),
    maxThreads: 1
  });

  const bufs = [
    new Int32Array(new SharedArrayBuffer(4)),
    new Int32Array(new SharedArrayBuffer(4))
  ];
  const task1 = pool.runTask(bufs[0]);
  const ee = new EventEmitter();
  rejects(pool.runTask(bufs[1], ee), /The task has been aborted/);
  rejects(pool.run(bufs[1], { signal: ee }), /The task has been aborted/);
  equal(pool.queueSize, 2);

  ee.emit('abort');

  // Wake up the thread handling the first task.
  Atomics.store(bufs[0], 0, 1);
  Atomics.notify(bufs[0], 0, 1);
  await task1;
});

test('abortable tasks will not share workers (abortable posted second)', async ({ equal, rejects }) => {
  const pool = new Piscina({
    filename: resolve(__dirname, 'fixtures/wait-for-notify.ts'),
    maxThreads: 1,
    concurrentTasksPerWorker: 2
  });

  const bufs = [
    new Int32Array(new SharedArrayBuffer(4)),
    new Int32Array(new SharedArrayBuffer(4))
  ];
  const task1 = pool.runTask(bufs[0]);
  const ee = new EventEmitter();
  rejects(pool.runTask(bufs[1], ee), /The task has been aborted/);
  equal(pool.queueSize, 1);

  ee.emit('abort');

  // Wake up the thread handling the first task.
  Atomics.store(bufs[0], 0, 1);
  Atomics.notify(bufs[0], 0, 1);
  await task1;
});

test('abortable tasks will not share workers (abortable posted first)', async ({ equal, rejects }) => {
  const pool = new Piscina({
    filename: resolve(__dirname, 'fixtures/eval.js'),
    maxThreads: 1,
    concurrentTasksPerWorker: 2
  });

  const ee = new EventEmitter();
  rejects(pool.runTask('while(true);', ee), /The task has been aborted/);
  const task2 = pool.runTask('42');
  equal(pool.queueSize, 1);

  ee.emit('abort');

  // Wake up the thread handling the second task.
  equal(await task2, 42);
});

test('abortable tasks will not share workers (on worker available)', async ({ equal }) => {
  const pool = new Piscina({
    filename: resolve(__dirname, 'fixtures/sleep.js'),
    maxThreads: 1,
    concurrentTasksPerWorker: 2
  });

  // Task 1 will sleep 100 ms then complete,
  // Task 2 will sleep 300 ms then complete.
  // Abortable task 3 should still be in the queue
  // when Task 1 completes, but should not be selected
  // until after Task 2 completes because it is abortable.

  const ret = await Promise.all([
    pool.runTask({ time: 100, a: 1 }),
    pool.runTask({ time: 300, a: 2 }),
    pool.runTask({ time: 100, a: 3 }, new EventEmitter())
  ]);

  equal(ret[0], 0);
  equal(ret[1], 1);
  equal(ret[2], 2);
});

test('abortable tasks will not share workers (destroy workers)', async ({ rejects }) => {
  const pool = new Piscina({
    filename: resolve(__dirname, 'fixtures/sleep.js'),
    maxThreads: 1,
    concurrentTasksPerWorker: 2
  });

  // Task 1 will sleep 100 ms then complete,
  // Task 2 will sleep 300 ms then complete.
  // Abortable task 3 should still be in the queue
  // when Task 1 completes, but should not be selected
  // until after Task 2 completes because it is abortable.

  pool.runTask({ time: 100, a: 1 }).then(() => {
    pool.destroy();
  });

  rejects(pool.runTask({ time: 300, a: 2 }), /Terminating worker thread/);
  rejects(pool.runTask({ time: 100, a: 3 }, new EventEmitter()),
    /Terminating worker thread/);
});

test('aborted AbortSignal rejects task immediately', async ({ rejects, equal }) => {
  const pool = new Piscina({
    filename: resolve(__dirname, 'fixtures/move.ts')
  });

  const controller = new AbortController();
  // Abort the controller early
  controller.abort();
  equal(controller.signal.aborted, true);

  // The data won't be moved because the task will abort immediately.
  const data = new Uint8Array(new SharedArrayBuffer(4));
  rejects(pool.runTask(data, [data.buffer], controller.signal),
    /The task has been aborted/);

  equal(data.length, 4);
});

test('task with AbortSignal cleans up properly', async ({ equal }) => {
  const pool = new Piscina({
    filename: resolve(__dirname, 'fixtures/eval.js')
  });

  const ee = new EventEmitter();

  await pool.runTask('1+1', ee);

  const { getEventListeners } = EventEmitter as any;
  if (typeof getEventListeners === 'function') {
    equal(getEventListeners(ee, 'abort').length, 0);
  }

  const controller = new AbortController();

  await pool.runTask('1+1', controller.signal);
});

test('aborted AbortSignal rejects task immediately (with reason)', async ({ match, equal }) => {
  const pool = new Piscina({
    filename: resolve(__dirname, 'fixtures/move.ts')
  });
  const customReason = new Error('custom reason');

  const controller = new AbortController();
  controller.abort(customReason);
  equal(controller.signal.aborted, true);
  equal(controller.signal.reason, customReason);

  // The data won't be moved because the task will abort immediately.
  const data = new Uint8Array(new SharedArrayBuffer(4));

  try {
    await pool.run(data, { transferList: [data.buffer], signal: controller.signal });
  } catch (error) {
    equal(error.message, 'The task has been aborted');
    match(error.cause, customReason);
  }

  equal(data.length, 4);
});

test('tasks can be aborted through AbortController while running', async ({ equal, match }) => {
  const pool = new Piscina({
    filename: resolve(__dirname, 'fixtures/notify-then-sleep.ts')
  });
  const reason = new Error('custom reason');

  const buf = new Int32Array(new SharedArrayBuffer(4));
  const abortController = new AbortController();

  try {
    const promise = pool.run(buf, { signal: abortController.signal });

    Atomics.wait(buf, 0, 0);
    equal(Atomics.load(buf, 0), 1);

    abortController.abort(reason);

    await promise;
  } catch (error) {
    equal(error.message, 'The task has been aborted');
    match(error.cause, reason);
  }
});