【问题标题】:Call external API until request is marked as complete调用外部 API 直到请求被标记为完成
【发布时间】:2019-02-04 07:24:56
【问题描述】:

我有以下情况。

我有一个服务,它在远程服务上运行作业并公开 API 以调用它。

我有一系列需要在远程服务器上执行的作业,并且在使用 Promises 时工作正常。

流程如下

在 main 函数中,我得到一个令牌。在相同的 .then() 上,我为作业启动我的 for 循环并传递 JobID 和令牌。第二个函数返回每个作业的 execution_ID。在第二个函数的 .then() 中,我传递了令牌和 execution_id。这将返回我的工作状态。

我的问题是;执行作业时,它会向我发送排队、启动和完成的状态。当状态变为“完成”时,我会得到工作结果;我需要显示。

我尝试在最后一个函数中使用 setTimeOut(),但我不确定它何时结束,因为每个作业可能需要不同的时间。

有没有办法可以多次调用第三个函数,除非状态更改为“已完成”?

下面是代码

app.get('/ExecuteJobs', function (req, res) {
var commandArraay = ["job1", "job2"]
var sTokenID;
getAuthToken()
    .then(function (token) {
        commandArraay.forEach(function (element) {
            getExecutionID(token, element)
                .then(function (executionResult) {
                    setTimeout(() => {
                        getExecutionResult(token, executionResult.id, executionResult)
                            .then(function (updateArray) {
                                console.log("Final Status " + "ID: " + executionResult.id + " Status: " + executionResult.status);
                                // if(executionResult.)
                            })
                    }, 10000)

                })
        })

    })
res.send('Done');
});



// Function to get the auth token
async function getAuthToken(token) {
    return new Promise(function (resolve, reject) {
        process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0;
        var pUserID = 'uname'
        var pPwd = 'pwd'
        performhttpsRequest('/<remote_api>/tokens', 'POST', {
            sAuth: "Basic " + new Buffer(pUserID + ":" +    pPwd).toString("base64")
    }, "0", token,
        function (data1) {
            sTokenID = data1.token;
            resolve(sTokenID);
        })
})
}
// Function to post the command and get execution ID
async function getExecutionID(tokenID, command, executionID) {
    return new Promise(function (resolve, reject) {
        performhttpsRequest('/<remote_api>/executecommand', 'POST', {
        command: command
    }, "1", tokenID,
        function (data1) {
            var executionID = data1.execution_id;
            resolve(executionID);
        })
})
}
// Function to get the execution results for an ID
async function getExecutionResult(tokenID, executionID, result) {
return new Promise(function (resolve, reject) {
    performhttpsRequest('/<remote_api>/execution_result/' + executionID, 'GET', {

    }, "1", tokenID,
        function (result) {
            resolve(result.result);
        })
})

}

【问题讨论】:

  • 请不要描述代码。改为发布。问题应包含stackoverflow.com/help/mcve
  • 如果您在排队的作业解决后绝对需要一个结果,那么除了每隔 n 秒重试检查一次状态之外,我看不出您还有其他选择。
  • 谢谢@NikKyriakides - 但这是主要问题。如果我理解正确;我不能使用 for 循环或 while 循环来继续检查。保持检查的方法是什么?
  • 一种方法是使用递归;我为你写了一个答案。

标签: node.js


【解决方案1】:

如果您在排队的作业解决后绝对需要结果,那么除了每隔 n 秒重试检查状态之外,我看不出您还有其他选择。

我会这样做。一个递归函数,重试请求 n 次,每次等待 n 秒:

// Mock request, resolves { status: 'completed' } 20% of the time.
const request = () => {
  return new Promise(resolve => {
    Math.random() < 0.2
      ? resolve({ status: 'completed', foo: 'bar' })
      : resolve({ status: 'pending' })
  })
}

const retryToCompletion = async ({ wait, retries }) => {
  console.log('Retries left:', retries)

  const result = await new Promise((resolve, reject) => {
    setTimeout(() => request().then(resolve).catch(reject), wait)
  })

  if (result.status === 'completed')
    return result

  if (retries)
    return retryToCompletion({ wait, retries: --retries })

  throw new Error('Retry attempts exhausted')
}

retryToCompletion({ wait: 1000, retries: 5 })
  .then(console.log)
  .catch(console.error)

话虽如此,一些与BASE 队列一起使用的API 提供了WebSocket 连接的句柄,该句柄会在作业完成时发出通知。如果 API 提供了该功能,那么您应该放弃重试并改用已完成的通知。

【讨论】:

  • 支持重试的东西。还有npm包retry
【解决方案2】:

进行 GET 调用直到完成

/**
 * cbk be called when..complete execution ok
 */
function completeExecution(tokenID, executionID, result, callPeriod, cbk){
    return getExecutionResult(tokenID, executionID, result).then(res=>{

        if(res.completed){
            return cbk(null, res)
        }

        setTimeout(function(){
            return completeExecution(cbk); //reenqueue
        }, callPeriod)
    }).catch(cbk) //up to you to abort or insist
}

然后你可以承诺completeExecution(与util.promisify或你自己)

【讨论】:

    猜你喜欢
    • 2021-02-16
    • 1970-01-01
    • 2020-06-29
    • 1970-01-01
    • 2020-07-22
    • 2020-07-12
    • 1970-01-01
    • 1970-01-01
    • 2016-07-03
    相关资源
    最近更新 更多