taskScheduler.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const configParser_1 = require("./configParser");
  4. /**
  5. * The taskScheduler keeps track of the spec files that needs to run next
  6. * and which task is running what.
  7. */
  8. class TaskQueue {
  9. // A queue of specs for a particular capacity
  10. constructor(capabilities, specLists) {
  11. this.capabilities = capabilities;
  12. this.specLists = specLists;
  13. this.numRunningInstances = 0;
  14. this.specsIndex = 0;
  15. this.maxInstance = capabilities.maxInstances || 1;
  16. }
  17. }
  18. exports.TaskQueue = TaskQueue;
  19. class TaskScheduler {
  20. /**
  21. * A scheduler to keep track of specs that need running and their associated
  22. * capabilities. It will suggest a task (combination of capabilities and spec)
  23. * to run while observing the following config rules:
  24. * multiCapabilities, shardTestFiles, and maxInstance.
  25. * Precondition: multiCapabilities is a non-empty array
  26. * (capabilities and getCapabilities will both be ignored)
  27. *
  28. * @constructor
  29. * @param {Object} config parsed from the config file
  30. */
  31. constructor(config) {
  32. this.config = config;
  33. let excludes = configParser_1.ConfigParser.resolveFilePatterns(config.exclude, true, config.configDir);
  34. let allSpecs = configParser_1.ConfigParser.resolveFilePatterns(configParser_1.ConfigParser.getSpecs(config), false, config.configDir)
  35. .filter((path) => {
  36. return excludes.indexOf(path) < 0;
  37. });
  38. let taskQueues = [];
  39. config.multiCapabilities.forEach((capabilities) => {
  40. let capabilitiesSpecs = allSpecs;
  41. if (capabilities.specs) {
  42. let capabilitiesSpecificSpecs = configParser_1.ConfigParser.resolveFilePatterns(capabilities.specs, false, config.configDir);
  43. capabilitiesSpecs = capabilitiesSpecs.concat(capabilitiesSpecificSpecs);
  44. }
  45. if (capabilities.exclude) {
  46. let capabilitiesSpecExcludes = configParser_1.ConfigParser.resolveFilePatterns(capabilities.exclude, true, config.configDir);
  47. capabilitiesSpecs = capabilitiesSpecs.filter((path) => {
  48. return capabilitiesSpecExcludes.indexOf(path) < 0;
  49. });
  50. }
  51. let specLists = [];
  52. // If we shard, we return an array of one element arrays, each containing
  53. // the spec file. If we don't shard, we return an one element array
  54. // containing an array of all the spec files
  55. if (capabilities.shardTestFiles) {
  56. capabilitiesSpecs.forEach((spec) => {
  57. specLists.push([spec]);
  58. });
  59. }
  60. else {
  61. specLists.push(capabilitiesSpecs);
  62. }
  63. capabilities.count = capabilities.count || 1;
  64. for (let i = 0; i < capabilities.count; ++i) {
  65. taskQueues.push(new TaskQueue(capabilities, specLists));
  66. }
  67. });
  68. this.taskQueues = taskQueues;
  69. this.rotationIndex = 0; // Helps suggestions to rotate amongst capabilities
  70. }
  71. /**
  72. * Get the next task that is allowed to run without going over maxInstance.
  73. *
  74. * @return {{capabilities: Object, specs: Array.<string>, taskId: string,
  75. * done: function()}}
  76. */
  77. nextTask() {
  78. for (let i = 0; i < this.taskQueues.length; ++i) {
  79. let rotatedIndex = ((i + this.rotationIndex) % this.taskQueues.length);
  80. let queue = this.taskQueues[rotatedIndex];
  81. if (queue.numRunningInstances < queue.maxInstance &&
  82. queue.specsIndex < queue.specLists.length) {
  83. this.rotationIndex = rotatedIndex + 1;
  84. ++queue.numRunningInstances;
  85. let taskId = '' + rotatedIndex + 1;
  86. if (queue.specLists.length > 1) {
  87. taskId += '-' + queue.specsIndex;
  88. }
  89. let specs = queue.specLists[queue.specsIndex];
  90. ++queue.specsIndex;
  91. return {
  92. capabilities: queue.capabilities,
  93. specs: specs,
  94. taskId: taskId,
  95. done: function () {
  96. --queue.numRunningInstances;
  97. }
  98. };
  99. }
  100. }
  101. return null;
  102. }
  103. /**
  104. * Get the number of tasks left to run or are currently running.
  105. *
  106. * @return {number}
  107. */
  108. numTasksOutstanding() {
  109. let count = 0;
  110. this.taskQueues.forEach((queue) => {
  111. count += queue.numRunningInstances + (queue.specLists.length - queue.specsIndex);
  112. });
  113. return count;
  114. }
  115. /**
  116. * Get maximum number of concurrent tasks required/permitted.
  117. *
  118. * @return {number}
  119. */
  120. maxConcurrentTasks() {
  121. if (this.config.maxSessions && this.config.maxSessions > 0) {
  122. return this.config.maxSessions;
  123. }
  124. else {
  125. let count = 0;
  126. this.taskQueues.forEach((queue) => {
  127. count += Math.min(queue.maxInstance, queue.specLists.length);
  128. });
  129. return count;
  130. }
  131. }
  132. /**
  133. * Returns number of tasks currently running.
  134. *
  135. * @return {number}
  136. */
  137. countActiveTasks() {
  138. let count = 0;
  139. this.taskQueues.forEach((queue) => {
  140. count += queue.numRunningInstances;
  141. });
  142. return count;
  143. }
  144. }
  145. exports.TaskScheduler = TaskScheduler;
  146. //# sourceMappingURL=taskScheduler.js.map