我正在尝试从节点脚本启动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);
}
});
});
}
答案 0 :(得分:1)
不太确定为什么你会在控制台中获得重复的结果,但下面是关于如何更好地编写代码的一些想法,主要是通过在最低级别进行宣传。
坚持原始概念,我最终得到了这个......
Promisify sc命令
.xxxAsync()
.done
作为.then
,Promise.resolve()应该能够同化命令返回的类似承诺的东西。;(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()强>
result
来检测成功路径中的错误情况。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
});
});
<强> tryServiceStart()强>
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');
}
});
}
<强> startService()强>
sc.query()
和sc.start()
console.log()
清除了投掷。 tryServiceStart()
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.');
}
});
}
仅检查语法错误,因此可能需要调试。
提供FWIW。随意采取/突袭。
答案 1 :(得分:0)
我找到了另一个名为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);
}
});
});
}