Невозможно выполнить обещание с помощью setTimeout - PullRequest
1 голос
/ 22 октября 2019

Я пишу функцию для записи в пожарный шланг AWS Kinesis с помощью Node. Вызов функции AWS, который записывает в поток пожарного шланга, возвращает «ошибку» или «данные» в зависимости от результата операции. В случае ошибки, для конкретного кода ошибки, мне нужно повторить тот же запрос с exponentialBackoff. Я использую setTimeOut для запуска одного и того же метода с переменным временем для каждой последующей повторной попытки, но похоже, что при каждой повторной попытке я не разрешаю должным образом, и мой тест терпит неудачу с жалобой " Ошибка: превышено время ожидания 5000 мс. Дляасинхронные тесты и перехватчики, убедитесь, что вызывается «done ()», при возврате Promise убедитесь, что он разрешается."

async function batchWrite(records,firehose,retry = 0){
    var readingObjects = getReadings(records);
    var params = {
        DeliveryStreamName: process.env.KINESIS_FIREHOSE_STREAM_DELIVERY,
        Records: readingObjects
    };

    return await new Promise(function(resolve,reject){
        firehose.putRecordBatch(params,function(error,data){
            if(error){
                if(error.code == 'ServiceUnavailableException' && retry < retries.length){
                    console.log('retryCount=',retry);
                    setTimeout(batchWrite,retries[retry],records,firehose,retry+1);
                    console.log('setTimeout',retry);
                }
                else{
                    // console.log('Error',error);
                    console.log('resolving');
                    resolve(error);
                }
            }
            else{
                if(data.FailedPutCount > 0){
                    //colect the RequestResponses which are not processed.
                    //index of those records is same as in request
                    //process those faied records again
                    console.log('Error',data);
                }
                resolve(data);
            }
        });
    });
}

для функции выше, в тестовом примере я симулирую ошибкуслучай, возвращая ответ с ServiceUnavailableException, так что он повторяет попытку, но после всех повторных попыток проверьте время ожидания. Есть ли что-то, что мне нужно изменить, чтобы оно заработало.

1 Ответ

0 голосов
/ 22 октября 2019

Когда вы вызываете setTimeout() для повторной попытки, исходное обещание, которое вы создали и вернули, никогда не разрешается. Таким образом, звонящий никогда не видит решенного обещания. Вам нужно будет связать новое обещание с предыдущим. И вы не можете сделать это с setTimeout() напрямую, но вы можете сделать это, когда я заверну это в свое обещание, а затем приковываю это к первоначальному обещанию. Кроме того, код становится намного более управляемым, если вы обещаете putRecordBatch как самый низкий уровень и выполняете весь свой поток управления с обещаниями, а не смесью обещаний и обратных вызовов.

Вот как это можно сделать:

// utility function to return a promise that is resolved after a setTimeout()
function delay(t, v) {
    return new Promise(resolve => {
        setTimeout(resolve, t, v);
    });
}

const promisify = require('util').promisify;

function batchWrite(records,firehose,retry = 0){
    var readingObjects = getReadings(records);
    var params = {
        DeliveryStreamName: process.env.KINESIS_FIREHOSE_STREAM_DELIVERY,
        Records: readingObjects
    };

    // make a promisified version of firehose.putRecordBatch
    firehose.putRecordBatchP = promisify(firehose.putRecordBatch);

    return firehose.putRecordBatchP(params).then(data => {
        if(data.FailedPutCount > 0){
            //collect the RequestResponses which are not processed.
            //index of those records is same as in request
            //process those failed records again
            console.log('Error',data);
        }
        return data;

    }).catch(error => {
        if(error.code == 'ServiceUnavailableException' && retry < retries.length){
            console.log('retryCount=',retry);

            // CHAIN the promise delay and retry here
            return delay(retries[retry]).then(() => {
                console.log('retry after delay #',retry);
                return batchWrite(records,firehose,retry+1); 
            });
        } else {
            // REJECT promise here upon error
            console.log('Error, rejecting promise');
            throw error;
        }

    });
}

Несколько вещей о вашем коде, которые я не понял:

  1. Когда вы получаете не повторяющуюся ошибку от putRecordBatch(), кажется, вы должны отклонить обещаниетак что звонящий знает, что операция не удалась. Я изменил код, чтобы сделать это.

  2. Мне не ясно, для чего предназначен пункт if(data.FailedPutCount > 0){...} или почему все, что вы делаете, - console.log() в нем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...