Home > Enterprise >  How to promise.race an array of async/sync callbacks vs a timeout when both are ran in parallel
How to promise.race an array of async/sync callbacks vs a timeout when both are ran in parallel

Time:11-13

I have a set of callbacks that may run on different durations before I close my web app. I also have a timeout where if it reaches past the timeout duration, I also close the application. The reason for this is to prevent the callbacks from blocking in closing the web app if it passes timeout duration.

Here is my current solution:

  public close() {
      const callbacks = this.onBeforeCloseCallbacks.map((cb) => new Promise(res => res(cb())));
      const timeout = new Promise((res) => setTimeout(res, TIMEOUT_DURATION));
      await Promise.race([Promise.all(callbacks), timeout]).then((value) => {
        // Currently returns Promise.all(callbacks) right away
        console.log(value)
      });
      await this.pluginEngine.close();
    }
  }

These are my tests

it('Should still close the plugin when timing out', async () => {
  // Arrange
  const cleanupMock = jest.fn();
  const cb1 = jest.fn().mockReturnValue(async () => new Promise(resolve => setTimeout(() => resolve(console.log('cb1')), 3000)));
  const cleanupMock2 = jest.fn();
  const cb2 = jest.fn().mockReturnValue(async () => new Promise(resolve => setTimeout(() => resolve(console.log('cb2')), 11000)));
  const placementCloseService = new PlacementCloseService(integrationMock, pluginInterface);

  // Act
  // onBeforeClose is registering callbacks that needs to be run before close
  placementCloseService.onBeforeClose(cb1);
  placementCloseService.onBeforeClose(cb2);
  await placementCloseService.close();

  // Assert
  expect(cleanupMock).toBeCalled();
  expect(cleanupMock2).not.toBeCalled();
  expect(pluginInterface.context.close).toBeCalled();
});

My current solution is returning Promise.all(callbacks) even if it hasn't called expected callbacks to run yet. What I expect to happen is that it passes through my timeout instead since it has a timer of 4000 and the last closeCallback has a timer of 5000.

What am I doing wrong?

CodePudding user response:

Your closeCallbacks are not async, You need them to return a promise.

const closeCallbacks = [
  // for sample purposes. i assigned timeouts to mock that it takes longer to run these callbacks then my timeout duration
  async () => new Promise(resolve => setTimeout(() => resolve(console.log('cb1')), 3000)),
  async () => new Promise(resolve => setTimeout(() => resolve(console.log('cb2')), 5000)),
];

CodePudding user response:

This creates a parameter named async not an async function

(async) => {}

Your timeout function never calls res parameter

const wait = (cb, time) => new Promise(r => { cb(); r() }, time)

const closeCallbacks = [
  () => wait(() => console.log('cb1'), 3000),
  () => wait(() => console.log('cb2'), 5000)
];

const timeout = new Promise((res) => setTimeout(() => console.log('timeout'); res(), 4000));
  • Related