我的快递服务器中有以下代码(为简洁起见,已将其删除)。我有一个共同的对象,我在三个不同的宁静终点添加/修改/阅读。由于nodejs中的所有http请求都是异步的,因此我可以同时获取put和get请求 。所以尽管PUT发生了但是我们说状态是而不是更新,我的GET可能会得到一个稍微陈旧的响应?
根据我的理解,我的测试显示这里没有竞争条件。因为更新results
对象是同步操作,所有异步操作都应该等待它。有人可以帮助更好地解释这是否正确吗?
var obj = {};
const exec = require('child_process').exec;
app.post('/foo', (req, res) => {
var result = {};
result.id = generateSomeRandomId();
result.failed = 0;
result.status = 'running'
//execute some command and update result
const child = exec('some command');
child.stdout.on('data', (data) => {
//some logic
});
child.stderr.on('data', (data) => {
result.failed = result.failed + 1;
});
child.on('close', (code, signal) => {
if (signal !== null && signal !== undefined) {
result.status = 'cancelled';
} else {
result.status = 'completed';
result.runtime = calculateRunTime();
}
});
result.pid = child.pid;
obj[result.id] = result;
res.send(result);
}
app.put('/foo/:id', (req, res) => {
var result = obj[req.params.id];
if (result.status === 'running' && result.pid !== undefined) {
kill(result.pid, 'SIGKILL');
result.status = 'cancelled';
result.runtime = calculateRunTime();
}
res.send(result);
}
app.get('/foo/:id', (req, res) => {
var result = obj[req.params.id];
res.send(result);
}
答案 0 :(得分:1)
这只是一个想法,但也许承诺在这里可能会有所帮助:
var obj = {};
const exec = require('child_process').exec;
app.post('/foo', (req, res) => {
var result = {};
result.id = generateSomeRandomId();
result.status = 'running';
const child = exec('some command');
child.stdout.on('data', (data) => {
//some logic
});
result.promise = new Promise(resolve => {
child.stderr.on('data', (data) => {
result.failed = result.failed + 1;
resolve(false);
});
child.on('close', (code, signal) => {
// ...
resolve(true);
});
});
result.pid = child.pid;
obj[result.id] = result;
res.send(result);
}
app.get('/foo/:id', (req, res) => {
var result = obj[req.params.id];
if(result.status === 'running') {
result.promise.then(() => res.send(result));
}
else {
res.send(result);
}
}
在这种情况下,GET仅在child
错误或“关闭”时才会响应。事件
答案 1 :(得分:1)
你没有任何我称之为“竞争条件”的东西;这里有一个不确定因素,但在实践中它并不重要。
看起来您的post
启动了一个流程并返回了ID,您的put
取消了流程,而您的get
会返回流程的当前状态。由此我得知,在get
完成并提供ID之前,您将永远无法post
。
如果您在get
异步侦听器完成之前收到并返回了exec
调用,您将获得最后一个正在进行的状态 - 我认为这是设计的。因此,唯一可能的冲突是,如果您已拨打put
来暂停您的流程。
在与结果对象进行交互时,put
和get
都是同步的,因此首先接收的是先完成的对象。您可以为我们的目的忽略进程取消请求,因为它不会修改结果对象。我们无法保证按照客户发送的订单顺序收到这些订单,这可能是也可能不是您方案中的实际问题。
我相信(虽然我的记忆可能有问题),如果您使用cluster
处理不同进程中的请求,则无法通过via传递数据无论如何,共享对象,因此已经排除了由这种可能性增加的任何复杂性。
因此,网络性能和可靠性的差异是您唯一真正的通配符。服务器将按照它们进入的顺序处理请求并为您提供预期的结果。如果你只有一个客户端,你可以等到你从之前的请求中得到响应,发送下一个请求,这可能会使你的性能无法接受,但要使其或多或少具有防弹性。否则,只需发送您的请求,不要担心,只需让您的应用程序足够健壮,以便识别&即使您已取消该流程,也会处理第二个取消请求。