Как вызывать API каждые 2 секунды до желаемого результата или тайм-аута в асинхронной функции - PullRequest
0 голосов
/ 10 октября 2018

Мне нужно вызывать API для получения состояния каждые 2 секунды, если ответ running, и первое возвращение, когда ответ либо complete, либо failed, либо до истечения 30 секунд и истечения времени ожидания функции.

Это то, что у меня сейчас работает, но я уверен, что это можно сделать гораздо эффективнее, но я просто не могу понять это в данный момент:

const getStatus = async (processId) => {
  try {
    const response = await fetch(`example.com/api/getStatus/${processId}`);
    const status = await response.json();

    return await status;
  } catch(err) {
    // handle error
  }
}

Внутридругая асинхронная функция с использованием getStatus ():

randomFunction = async () => {
  let status = null;
  let tries = 0;
  let stop = false;

  while (tries <= 15 && !stop) {
    try {
      status = await getStatus('some-process-id');

      if (status === 'complete') {
        stop = true;
        // do something outside of loop
      }

      if (status === 'failed') {
        stop = true;
        throw Error(status);
      }

      if (tries === 15) {
        stop = true;
        throw Error('Request timed out');
      }
    } catch (err) {
      // handle error
    }

    const delay = time => new Promise(resolve => setTimeout(() => resolve(), time));

    if (tries < 15) {
      await delay(2000);
    }

    tries++;
  }
}

Я бы предпочел обрабатывать циклы внутри getStatus() и в более читаемом формате, но возможно ли это?

EDIT: Я попробовал решение, которое выглядит лучше и, кажется, работает так, как я ожидаю, смотрите здесь:

https://gist.github.com/AntonBramsen/6cec0faade032dfa3c175b7d291e07bd

Дайте мне знать, если части решения содержат какие-либо решения, которыеплохая практика.

1 Ответ

0 голосов
/ 11 октября 2018

Ваш вопрос для javascript.К сожалению, я не пью кофе, я могу дать вам только код на C #.Но я думаю, вы понимаете суть и можете выяснить, как перевести это в java

Давайте сделаем это как универсальную функцию:

У вас есть функция, которая вызывается каждые TimeSpan, иВы хотите прекратить вызывать эту функцию всякий раз, когда функция возвращает true, вы хотите отменить ее, когда прошло какое-то максимальное время.

Для этого максимального времени я использую CancellationToken, это позволяет отменить обработкупо большим причинам, чем по таймауту.Например, потому что оператор хочет закрыть программу.

TapiResult CallApi<TapiResult> <Func<TapiResult> apiCall,
    Func<TapiResult, bool> stopCriterion,
    CancellationToken cancellationToken)
{
    TapiResult apiResult = apiCall;
    while (!stopCriterion(apiResult))
    {
        cancellationToken.ThrowIfCancellationRequested();
        Task.Delay(delayTime, cancellationToken).Wait;
        apiResult = apiCall;
    }
    return apiResult;

}

  • ApiCall - это функция Api для вызова.Возвращаемое значение равно TApiResult.В вашем случае status - это ваша TApiResult
  • StopCriterion - это функция с входом ApiResult и выходным логическим значением, которое имеет значение true, когда функция должна остановиться.В вашем случае это когда status равно complete или failed
  • CancellationToken - это Token, которое вы можете получить от CancellationTokenSource.Всякий раз, когда вы хотите, чтобы процедура прекратила обработку, просто скажите CancellationTokenSource, и функция остановится с CancellationException

Предположим, это ваш Api:

Status MyApiCall(int x, string y) {...}

Тогда используется:

Timespan maxProcessTime = TimeSpan.FromSeconds(45);
var cancellationTokenSource = new CancellationTokenSource();

// tell the cancellationTokenSource to stop processing afer maxProcessTime:
cancellationTokenSource.CancelAfter(maxProcessTime);

// Start processing
Status resultAfterProcessing = CallApi<Status>(
   () => MyApiCall (3, "Hello World!"),        // The Api function to call repeatedly
                                               // it returns a Status
   (status) => status == complete              // stop criterion: becomes true
            || status == failed,               // when status complete or failed
   cancellationTokenSource.Token);             // get a token from the token source

TODO: добавьте try / catch для CancellationException и обработайте то, что нужно сделать, если задача отменяется

Функция остановится, как только stopCriterion станет истиннымили когда CancellationTokenSource отменяется.Это будет сделано автоматически после maxTimeOut.Однако, если вы хотите остановить раньше, например, потому что хотите остановить программу:

cancellationTokenSource.Cancel();
...