Typescript timeout Decorator to stop while loop

Viewed 37

I have timeout decorator, which works fine, but when decorating function which have while loop, it constantly calls the decorator even if it throws.

Decorator function:

export function asyncCallWithTimeoutDecorator(timeLimit: number) {
  return function (
    target: Object,
    key: string,
    descriptor: PropertyDescriptor
  ): any {
    let method = descriptor.value;

    descriptor.value = async function (...args: any) {
      let timeoutHandle: any;
      try {
        const timeoutPromise = new Promise((_resolve, reject) => {
          timeoutHandle = setTimeout(
            () =>
              reject(
                new Error(
                  JSON.stringify({
                    message: `Execution Time Limit Reached! Timeout after ${timeLimit}ms`,
                    continueExecution: false,
                  })
                )
              ),
            timeLimit
          );
        });

        let callMethod = method.apply(this, args);

        let result = await Promise.race([callMethod, timeoutPromise]);

        clearTimeout(timeoutHandle);
        return result;
      } catch (e: any) {
        throw new Error(e);
      }
    };
  };
}

Usage:

  @asyncCallWithTimeoutDecorator(1000)
  async expect(
    taskHttpPayload: HttpActionRequest,
    expected: string
  ): Promise<any> {
    let response: any = await this.run(taskHttpPayload);

    let confirmed = objectFindValueByKey(response, expected);

    while (!confirmed) {
      confirmed = objectFindValueByKey(response, expected);

      await wait(1000); // wait 1 second
      response = await this.run(taskHttpPayload);
    }

    return {};
  }
}

When this is run on function without the while loop, in case of timeout, decorator throws error and it ends execution. When this is run on function with while while loop, in case of timeout, decorator throws error, but while loop continues to call "await this.run" which calls the decorator.

Is there a nice way to pass parameter to while loop to stop it or another way?

I very nasty option is to add into the decorator, before throw:

args[0].stopExecution = true

where in while loop we can check then for:

while(!target.stopExecution && !confirmed)

--->

I found better solution. I've implemented in my HTTP library:

public controller = new AbortController();

and pass this to request:

return await this.instance.request({
      url: `${this.url}${request.path}`,
      data: request.data ? request.data : undefined,
      method,
      headers,
      timeout: this.timeout,
      signal: this.controller.signal
    });

and it the Decorator in the catch, when exception is raise by Promise.race because of the timeout:

_this.httpClient.controller.abort(e);

which send stop signal to the async execution. No need fo additional check, just on timeout exception, abort it :)

0 Answers
Related