child-pool.js 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import * as path from 'path';
  2. import { Child } from './child';
  3. const CHILD_KILL_TIMEOUT = 30000;
  4. const supportCJS = () => {
  5. return (typeof require === 'function' &&
  6. typeof module === 'object' &&
  7. typeof module.exports === 'object');
  8. };
  9. export class ChildPool {
  10. constructor({ mainFile = supportCJS()
  11. ? path.join(process.cwd(), 'dist/cjs/classes/main.js')
  12. : path.join(process.cwd(), 'dist/esm/classes/main.js'), useWorkerThreads, workerForkOptions, workerThreadsOptions, }) {
  13. this.retained = {};
  14. this.free = {};
  15. this.opts = {
  16. mainFile,
  17. useWorkerThreads,
  18. workerForkOptions,
  19. workerThreadsOptions,
  20. };
  21. }
  22. async retain(processFile) {
  23. let child = this.getFree(processFile).pop();
  24. if (child) {
  25. this.retained[child.pid] = child;
  26. return child;
  27. }
  28. child = new Child(this.opts.mainFile, processFile, {
  29. useWorkerThreads: this.opts.useWorkerThreads,
  30. workerForkOptions: this.opts.workerForkOptions,
  31. workerThreadsOptions: this.opts.workerThreadsOptions,
  32. });
  33. child.on('exit', this.remove.bind(this, child));
  34. try {
  35. await child.init();
  36. // Check status here as well, in case the child exited before we could
  37. // retain it.
  38. if (child.exitCode !== null || child.signalCode !== null) {
  39. throw new Error('Child exited before it could be retained');
  40. }
  41. this.retained[child.pid] = child;
  42. return child;
  43. }
  44. catch (err) {
  45. console.error(err);
  46. this.release(child);
  47. throw err;
  48. }
  49. }
  50. release(child) {
  51. delete this.retained[child.pid];
  52. this.getFree(child.processFile).push(child);
  53. }
  54. remove(child) {
  55. delete this.retained[child.pid];
  56. const free = this.getFree(child.processFile);
  57. const childIndex = free.indexOf(child);
  58. if (childIndex > -1) {
  59. free.splice(childIndex, 1);
  60. }
  61. }
  62. async kill(child, signal = 'SIGKILL') {
  63. this.remove(child);
  64. return child.kill(signal, CHILD_KILL_TIMEOUT);
  65. }
  66. async clean() {
  67. const children = Object.values(this.retained).concat(this.getAllFree());
  68. this.retained = {};
  69. this.free = {};
  70. await Promise.all(children.map(c => this.kill(c, 'SIGTERM')));
  71. }
  72. getFree(id) {
  73. return (this.free[id] = this.free[id] || []);
  74. }
  75. getAllFree() {
  76. return Object.values(this.free).reduce((first, second) => first.concat(second), []);
  77. }
  78. }
  79. //# sourceMappingURL=child-pool.js.map