sandbox.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const enums_1 = require("../enums");
  4. const sandbox = (processFile, childPool) => {
  5. return async function process(job, token, signal) {
  6. let child;
  7. let msgHandler;
  8. let exitHandler;
  9. let abortHandler;
  10. try {
  11. const done = new Promise((resolve, reject) => {
  12. const initChild = async () => {
  13. try {
  14. exitHandler = (exitCode, signal) => {
  15. reject(new Error('Unexpected exit code: ' + exitCode + ' signal: ' + signal));
  16. };
  17. child = await childPool.retain(processFile);
  18. child.on('exit', exitHandler);
  19. msgHandler = async (msg) => {
  20. var _a, _b, _c, _d, _e;
  21. try {
  22. switch (msg.cmd) {
  23. case enums_1.ParentCommand.Completed:
  24. resolve(msg.value);
  25. break;
  26. case enums_1.ParentCommand.Failed:
  27. case enums_1.ParentCommand.Error: {
  28. const err = new Error();
  29. Object.assign(err, msg.value);
  30. reject(err);
  31. break;
  32. }
  33. case enums_1.ParentCommand.Progress:
  34. await job.updateProgress(msg.value);
  35. break;
  36. case enums_1.ParentCommand.Log:
  37. await job.log(msg.value);
  38. break;
  39. case enums_1.ParentCommand.MoveToDelayed:
  40. await job.moveToDelayed((_a = msg.value) === null || _a === void 0 ? void 0 : _a.timestamp, (_b = msg.value) === null || _b === void 0 ? void 0 : _b.token);
  41. break;
  42. case enums_1.ParentCommand.MoveToWait:
  43. await job.moveToWait((_c = msg.value) === null || _c === void 0 ? void 0 : _c.token);
  44. break;
  45. case enums_1.ParentCommand.MoveToWaitingChildren:
  46. {
  47. const value = await job.moveToWaitingChildren((_d = msg.value) === null || _d === void 0 ? void 0 : _d.token, (_e = msg.value) === null || _e === void 0 ? void 0 : _e.opts);
  48. child.send({
  49. requestId: msg.requestId,
  50. cmd: enums_1.ChildCommand.MoveToWaitingChildrenResponse,
  51. value,
  52. });
  53. }
  54. break;
  55. case enums_1.ParentCommand.Update:
  56. await job.updateData(msg.value);
  57. break;
  58. case enums_1.ParentCommand.GetChildrenValues:
  59. {
  60. const value = await job.getChildrenValues();
  61. child.send({
  62. requestId: msg.requestId,
  63. cmd: enums_1.ChildCommand.GetChildrenValuesResponse,
  64. value,
  65. });
  66. }
  67. break;
  68. case enums_1.ParentCommand.GetIgnoredChildrenFailures:
  69. {
  70. const value = await job.getIgnoredChildrenFailures();
  71. child.send({
  72. requestId: msg.requestId,
  73. cmd: enums_1.ChildCommand.GetIgnoredChildrenFailuresResponse,
  74. value,
  75. });
  76. }
  77. break;
  78. case enums_1.ParentCommand.GetDependenciesCount:
  79. {
  80. const value = await job.getDependenciesCount(msg.value);
  81. child.send({
  82. requestId: msg.requestId,
  83. cmd: enums_1.ChildCommand.GetDependenciesCountResponse,
  84. value,
  85. });
  86. }
  87. break;
  88. case enums_1.ParentCommand.GetDependencies:
  89. {
  90. const value = await job.getDependencies(msg.value);
  91. child.send({
  92. requestId: msg.requestId,
  93. cmd: enums_1.ChildCommand.GetDependenciesResponse,
  94. value,
  95. });
  96. }
  97. break;
  98. }
  99. }
  100. catch (err) {
  101. reject(err);
  102. }
  103. };
  104. child.on('message', msgHandler);
  105. child.send({
  106. cmd: enums_1.ChildCommand.Start,
  107. job: job.asJSONSandbox(),
  108. token,
  109. });
  110. if (signal) {
  111. abortHandler = () => {
  112. try {
  113. child.send({
  114. cmd: enums_1.ChildCommand.Cancel,
  115. value: signal.reason,
  116. });
  117. }
  118. catch (_a) {
  119. // Child process may have already exited
  120. }
  121. };
  122. if (signal.aborted) {
  123. abortHandler();
  124. }
  125. else {
  126. signal.addEventListener('abort', abortHandler, { once: true });
  127. }
  128. }
  129. }
  130. catch (error) {
  131. reject(error);
  132. }
  133. };
  134. initChild();
  135. });
  136. await done;
  137. return done;
  138. }
  139. finally {
  140. // Note: There is a potential race where the signal is aborted between
  141. // `await done` and this cleanup. This is safe because:
  142. // 1. abortHandler has a try-catch for child process already exited
  143. // 2. The listener is added with `once: true`, so it fires at most once
  144. // 3. removeEventListener here is defensive cleanup only
  145. if (signal && abortHandler) {
  146. signal.removeEventListener('abort', abortHandler);
  147. }
  148. if (child) {
  149. child.off('message', msgHandler);
  150. child.off('exit', exitHandler);
  151. if (child.exitCode === null && child.signalCode === null) {
  152. childPool.release(child);
  153. }
  154. }
  155. }
  156. };
  157. };
  158. exports.default = sandbox;
  159. //# sourceMappingURL=sandbox.js.map