timeoutRunner.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.TimeoutRunnerError = exports.TimeoutRunner = exports.MaxTime = void 0;
  6. exports.pollAgainstDeadline = pollAgainstDeadline;
  7. exports.raceAgainstDeadline = raceAgainstDeadline;
  8. var _manualPromise = require("./manualPromise");
  9. var _ = require("./");
  10. /**
  11. * Copyright (c) Microsoft Corporation.
  12. *
  13. * Licensed under the Apache License, Version 2.0 (the "License");
  14. * you may not use this file except in compliance with the License.
  15. * You may obtain a copy of the License at
  16. *
  17. * http://www.apache.org/licenses/LICENSE-2.0
  18. *
  19. * Unless required by applicable law or agreed to in writing, software
  20. * distributed under the License is distributed on an "AS IS" BASIS,
  21. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  22. * See the License for the specific language governing permissions and
  23. * limitations under the License.
  24. */
  25. class TimeoutRunnerError extends Error {}
  26. exports.TimeoutRunnerError = TimeoutRunnerError;
  27. const MaxTime = exports.MaxTime = 2147483647; // 2^31-1
  28. class TimeoutRunner {
  29. constructor(timeout) {
  30. this._running = void 0;
  31. this._timeout = void 0;
  32. this._elapsed = void 0;
  33. this._deadline = MaxTime;
  34. this._timeout = timeout;
  35. this._elapsed = 0;
  36. }
  37. async run(cb) {
  38. const running = this._running = {
  39. lastElapsedSync: (0, _.monotonicTime)(),
  40. timer: undefined,
  41. timeoutPromise: new _manualPromise.ManualPromise()
  42. };
  43. try {
  44. const resultPromise = Promise.race([cb(), running.timeoutPromise]);
  45. this._updateTimeout(running, this._timeout);
  46. return await resultPromise;
  47. } finally {
  48. this._updateTimeout(running, 0);
  49. if (this._running === running) this._running = undefined;
  50. }
  51. }
  52. interrupt() {
  53. if (this._running) this._updateTimeout(this._running, -1);
  54. }
  55. elapsed() {
  56. this._syncElapsedAndStart();
  57. return this._elapsed;
  58. }
  59. deadline() {
  60. return this._deadline;
  61. }
  62. updateTimeout(timeout, elapsed) {
  63. this._timeout = timeout;
  64. if (elapsed !== undefined) {
  65. this._syncElapsedAndStart();
  66. this._elapsed = elapsed;
  67. }
  68. if (this._running) this._updateTimeout(this._running, timeout);
  69. }
  70. _syncElapsedAndStart() {
  71. if (this._running) {
  72. const now = (0, _.monotonicTime)();
  73. this._elapsed += now - this._running.lastElapsedSync;
  74. this._running.lastElapsedSync = now;
  75. }
  76. }
  77. _updateTimeout(running, timeout) {
  78. if (running.timer) {
  79. clearTimeout(running.timer);
  80. running.timer = undefined;
  81. }
  82. this._syncElapsedAndStart();
  83. this._deadline = timeout ? (0, _.monotonicTime)() + timeout : MaxTime;
  84. if (timeout === 0) return;
  85. timeout = timeout - this._elapsed;
  86. if (timeout <= 0) running.timeoutPromise.reject(new TimeoutRunnerError());else running.timer = setTimeout(() => running.timeoutPromise.reject(new TimeoutRunnerError()), timeout);
  87. }
  88. }
  89. exports.TimeoutRunner = TimeoutRunner;
  90. async function raceAgainstDeadline(cb, deadline) {
  91. const runner = new TimeoutRunner((deadline || MaxTime) - (0, _.monotonicTime)());
  92. try {
  93. return {
  94. result: await runner.run(cb),
  95. timedOut: false
  96. };
  97. } catch (e) {
  98. if (e instanceof TimeoutRunnerError) return {
  99. timedOut: true
  100. };
  101. throw e;
  102. }
  103. }
  104. async function pollAgainstDeadline(callback, deadline, pollIntervals = [100, 250, 500, 1000]) {
  105. var _pollIntervals$pop;
  106. const lastPollInterval = (_pollIntervals$pop = pollIntervals.pop()) !== null && _pollIntervals$pop !== void 0 ? _pollIntervals$pop : 1000;
  107. let lastResult;
  108. const wrappedCallback = () => Promise.resolve().then(callback);
  109. while (true) {
  110. var _shift;
  111. const time = (0, _.monotonicTime)();
  112. if (deadline && time >= deadline) break;
  113. const received = await raceAgainstDeadline(wrappedCallback, deadline);
  114. if (received.timedOut) break;
  115. lastResult = received.result.result;
  116. if (!received.result.continuePolling) return {
  117. result: lastResult,
  118. timedOut: false
  119. };
  120. const interval = (_shift = pollIntervals.shift()) !== null && _shift !== void 0 ? _shift : lastPollInterval;
  121. if (deadline && deadline <= (0, _.monotonicTime)() + interval) break;
  122. await new Promise(x => setTimeout(x, interval));
  123. }
  124. return {
  125. timedOut: true,
  126. result: lastResult
  127. };
  128. }