Javascript 停止NodeJs promise while循环中的多个服务控制器查询

Javascript 停止NodeJs promise while循环中的多个服务控制器查询,javascript,node.js,promise,gulp,service-control-manager,Javascript,Node.js,Promise,Gulp,Service Control Manager,我正在尝试从节点脚本启动windows服务。此服务有挂起的坏习惯,有时需要重试才能成功启动。我有一个承诺,而循环设置(请随时建议一个更好的方式)。我遇到的问题是,对于每个循环,sc.pollInterval输出在控制台中写入重复的结果。下面是我在控制台中看到的重复内容的示例,这是在循环中的第二次迭代之后,我希望它只显示该内容一次 sc \\abnf34873 start ColdFusion 10 Application Server sc \\abnf34873 queryex ColdFu

我正在尝试从节点脚本启动windows服务。此服务有挂起的坏习惯,有时需要重试才能成功启动。我有一个承诺,而循环设置(请随时建议一个更好的方式)。我遇到的问题是,对于每个循环,
sc.pollInterval
输出在控制台中写入重复的结果。下面是我在控制台中看到的重复内容的示例,这是在循环中的第二次迭代之后,我希望它只显示该内容一次

sc \\abnf34873 start ColdFusion 10 Application Server

sc \\abnf34873 queryex ColdFusion 10 Application Server

SERVICE_NAME: ColdFusion 10 Application Server
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 2  START_PENDING
                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x7d0
        PID                : 0
        FLAGS              :

SERVICE_NAME: ColdFusion 10 Application Server
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 2  START_PENDING
                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x7d0
        PID                : 13772
        FLAGS              :
这是我的密码。基本上,我将尝试启动服务3次。如果没有,我就会抛出错误。需要注意的一点是,当我试图启动服务,但它仍停留在“start_pending”状态时,我会终止该进程,然后再次尝试启动它

var retryCount = 0;

// Start the colfusion service
gulp.task('start-coldfusion-service', function(done) {
    var serviceStarted = false;
    console.log("Starting coldfusion service..");
    // This says we're going to ask where it's at every 30 seconds until it's in the desired state.
    sc.pollInterval(30);
    sc.timeout(60);
    retryCount = 0;

    tryServiceStart().then(function(result) {
          // process final result here
        done();
    }).catch(function(err) {
        // process error here
    });
});


function tryServiceStart() {
    return startService().then(function(serviceStarted) {
        if (serviceStarted == false) {
            console.log("Retry Count: " + retryCount);
            // Try again..
            return tryServiceStart();
        } else {
             return result;
        }
    });
}

function startService() {
    return new Promise(function(resolve, reject) {
        var started = true;
        // Make sure the coldfusion service exists on the target server
        sc.query(targetServer, { name: 'ColdFusion 10 Application Server'}).done(function(services) {
            // if the service exists and it is currentl stopped, then we're going to start it.
            if (services.length == 1) {
                var pid = services[0].pid;
                if (services[0].state.name == 'STOPPED') {
                    sc.start(targetServer, 'ColdFusion 10 Application Server')
                        .catch(function(error) {
                            started = false;
                            console.log("Problem starting Coldfusion service! error message: " + error.message);
                            console.log("retrying...");
                            retryCount++;
                            if (parseInt(retryCount) > 2) {
                                throw Error(error.message);
                            }
                       })
                       .done(function(displayName) {
                            if (started) {
                                console.log('Coldfusion service started successfully!');
                            }
                            resolve(started);
                       });
                } else if (services[0].state.name == 'START_PENDING') {
                    kill(pid, {force: true}).catch(function (err) {
                        console.log('Problem killing process..');
                    }).then(function() {
                        console.log('Killed hanging process..');
                        resolve(false);
                    });
                }
            } else {
                console.log("Could not find the service in a stopped state.");
                resolve(false);
            }
        });
   });
}

我发现另一个名为
promise retry
的npm包似乎解决了我遇到的问题。同时,我相信它使我的代码更清楚地知道它在做什么

gulp.task('start-coldfusion-service', function(done) {
    var serviceStarted = false;
    console.log("Starting coldfusion service..");
    // Since starting a service on another server isn't exactly fast, we have to poll the status of it.
    // This says we're going to ask where it's at every 30 seconds until it's in the desired state.
    sc.pollInterval(30);
    sc.timeout(60);     

    promiseRetry({retries: 3}, function (retry, number) {
        console.log('attempt number', number);

        return startService()
        .catch(function (err) {
            console.log(err);
            if (err.code === 'ETIMEDOUT') {
                retry(err);
            } else if (err === 'killedProcess') {
                retry(err);
            }

            throw Error(err);
        });
    })
    .then(function (value) {
        done();
    }, function (err) {
        console.log("Unable to start the service after 3 tries!");
        process.exit();
    });

});

function startService() {
    var errorMsg = "";
    return new Promise(function(resolve, reject) {
        var started = true;
        // Make sure the coldfusion service exists on the target server
        sc.query(targetServer, { name: 'ColdFusion 10 Application Server'}).done(function(services) {
            // if the service exists and it is currentl stopped, then we're going to start it.
            if (services.length == 1) {
                var pid = services[0].pid;
                if (services[0].state.name == 'STOPPED') {
                    sc.start(targetServer, 'ColdFusion 10 Application Server')
                        .catch(function(error) {
                            started = false;
                            errorMsg = error;
                            console.log("Problem starting Coldfusion service! error message: " + error.message);
                            console.log("retrying...");
                       })
                       .done(function(displayName) {
                            if (started) {
                                console.log('Coldfusion service started successfully!');
                                resolve(started);
                            } else {
                                reject(errorMsg);
                            }
                       });
                } else if (services[0].state.name == 'START_PENDING') {
                    kill(pid, {force: true}).catch(function (err) {
                        console.log('Problem killing process..');
                    }).then(function() {
                        console.log('Killed hanging process..');
                        reject("killedProcess");
                    });
                } else {
                    // Must already be started..
                    resolve(true);
                }
            } else {
                console.log("Could not find the service in a stopped state.");
                resolve(false);
            }
        });

   });

}

不太清楚为什么会在控制台中得到重复的结果,但是下面是一些关于如何更好地编写代码的想法,主要是通过在最低级别上进行承诺

坚持原来的概念,我最终得到了这个

提示sc命令

  • sc命令返回类似于promise的东西,但带有一个.done()方法,该方法很可能不具有真正的.then()方法的全部功能
  • 将每个命令显示为
    .xxxAsync()
  • 通过采用每个命令的
    .done
    作为
    。然后
    ,Promise.resolve()应该能够吸收命令返回的类似于Promise的内容
吞咽任务()

  • 如果服务已打开,承诺链将遵循其成功路径,否则将遵循其错误路径
  • 无需测试
    结果
    ,即可检测成功路径中的错误情况
tryServiceStart()

  • 在此处编排重试
启动服务()

  • 通过调用
    sc.query()
    sc.start()
  • console.log()
    
  • 抛出的错误将被捕获并记录回
    tryServiceStart()
只检查语法错误,因此可能需要调试


提供FWIW。可以根据需要随意采用/raid。

service control manager软件包声称“所有命令都返回一个承诺”,但是文档(您的代码正确遵守了该文档)告诉我们,这些所谓的承诺包含
.done()
.catch()
方法。现在还不清楚
.done()
是否拥有适当的
的全部功能。然后()
或者
.done()
是否只是像jQuery的
.done()
那样的蹩脚东西。这些例子说明了后者,我在网上找不到任何与此相反的信息。谢谢@Roamer-1888提供的信息。我相信您是对的,因为它类似于JQuery的
.done()
方法,因为无论承诺是被拒绝还是被解决,它内部的内容每次都会执行。无论如何,我已经找到了一个使用Promise retry软件包的解决方案。我很快会将新代码作为答案发布。Jmh2013,今天早些时候我曾尝试过一些想法。当我回到桌面时,我会将它们作为答案发布。小心返回(我们假设)承诺的
kill()
。如果是这样,那么使用
kill(…)。catch(…)。然后(…);
,除非
catch
回调抛出/rethow,否则执行将下降到
then
回调。您将在我的解决方案中看到,我颠倒了读取
kill(…)。然后(…).catch(…);
。即使有了这种颠倒,也要确保catch回调调用
reject()
;记录是不够的。此外,为了一致性,请始终拒绝(或抛出)一个正确的
错误
,而不是
字符串
。这样,所有下游捕获都可以被写入以接收
错误
,而不管它是如何发生的/在哪里发生的。感谢您的提示。我已经更新了我的代码,使其与您的答案相似。因此,我相信,我现在已经处理好了。这是我第一次使用Node并使用w非常感谢您的帮助!我的脚本的这一部分现在工作得很好!很抱歉我的回复太晚了,我正在休假。我真的很喜欢您在这里所做的事情。不过,我在控制台中仍然收到重复的结果。
promise retry
软件包为我修复了这一问题。因此我删除了
tryServiceStart()
函数,我正在使用
Promise retry
包来协调“启动coldfusion服务”任务中的重试。我采用的代码与您这里的代码非常匹配。我特别喜欢错误会像现在这样冒出来。我不确定是什么导致了重复的结果,或者为什么Promise retry会失败我的代码的行为和承诺重试之间肯定有一些微妙的区别,但对于我来说,我无法想象它可能是什么。无论如何,重要的是你有一个解决方案。祝你好运。
;(function() {
    commands.forEach(command => {
        sc[command].then = sc[command].done;
        sc[command + 'Async'] = function() {
            return Promise.resolve(sc[command](...arguments)); 
        };
    }).
}(['start', 'query'])); // add other commands as required
gulp.task('start-coldfusion-service', function(done) {
    console.log('Starting coldfusion service..');
    // This says we're going to ask where it's at every 30 seconds until it's in the desired state.
    sc.pollInterval(30);
    sc.timeout(60);
    tryServiceStart(2) // tryServiceStart(maxRetries)
    .then(done) // success! The service was started.
    .catch(function(err) {
        // the only error to end up here should be 'Maximum tries reached'.
        console.err(err);
        // process error here if necessary
    });
});
function tryServiceStart(maxRetries) {
    return startService()
    // .then(() => {}) // success! No action required here, just stay on the success path.
    .catch((error) => {
        // all throws from startService() end up here
        console.error(error); // log intermediate/final error
        if(--maxRetries > 0) {
            return tryServiceStart();
        } else {
            throw new Error('Maximum tries reached');
        }
    });
}
function startService() {
    // Make sure the coldfusion service exists on the target server
    return sc.queryAsync(targetServer, { name: 'ColdFusion 10 Application Server'})
    .then((services) => {
        // if the service exists and it is currently stopped, then start it.
        if (services.length == 1) {
            switch(services[0].state.name) {
                case 'STOPPED':
                    return sc.startAsync(targetServer, 'ColdFusion 10 Application Server')
                    .catch((error) => {
                        throw new Error("Problem starting Coldfusion service! error message: " + error.message);
                    });
                break;
                case 'START_PENDING':
                    return kill(services[0].pid, { 'force': true })
                    .then(() => {
                        throw new Error('Killed hanging process..'); // successful kill but still an error as far as startService() is concerned.
                    })
                    .catch((err) => {
                        throw new Error('Problem killing process..');
                    });
                break;
                default:
                    throw new Error("Service not in a stopped state.");
            }
        } else {
            throw new Error('Could not find the service.');
        }
    });
}