2017-11-12 1 views
1

나는 익스프레스 서버에 다음 코드를 가지고 있습니다 (간단히하기 위해 줄였습니다). 나는 세 가지 다른 편안한 종말점에서 내가 추가/수정/읽는 공통 대상을 가지고있다. nodejs의 모든 HTTP 요청이 비동기 적이기 때문에 동시에 넣고 가져올 수 있습니다. . 따라서 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

당신은'app.post ('/ foo'')에 대해 이야기하고 있습니까? "race"는 없지만 비동기 부분이 실행되기 전에'res.post (result);' 당신이''어떤 명령을 실행하고 결과를 갱신하고''result.pid = child ''사이에 무엇을 하든지간에.pid;는'res.send (result);에서 보낸 내용에 아무런 영향을주지 않을 것입니다. –

+0

또한'result.failed = result.failed + 1;'은'results.failed'가'undefined'이거나, 오류가 있으면'result.failed === NaN' –

+0

@ JaromandaX 예 그 부분을 얻습니다. * post *의 모든 비동기 작업은 모든 동기화 작업이 완료 될 때까지 대기합니다. 내 질문은 대부분 동시 PUT 및 GET 요청에있었습니다. 거기에 경쟁 조건이 있겠습니까? 그리고 당신은 결과에 대해 옳았습니다. NaN 부분을 무시하고 간단하게 초기화를 생략했습니다. 그것을 다시 추가 할 것입니다. – Manali

답변

1

"경쟁 조건"이라고 할만한 것이 없습니다. 여기서 불확실성이있는 요소가 있지만 실제로는 문제가되지 않을 것입니다.

post이 프로세스를 시작하고 ID를 반환하는 것처럼 보입니다. put은 프로세스를 취소하고 get은 프로세스의 현재 상태를 반환합니다. 이것에서 당신은 당신의 post가 완료되고 ID를 제공 할 때까지 결코 get에 갈 수 없다는 것을 모았습니다.

exec 비동기식 수신기가 완료되기 전에 get 호출을 수신하고 반환하면 마지막으로 진행중인 상태가 무엇인지 알 수 있습니다. 이는 의도적으로 생각한 것입니다. 따라서 여기에서 가능한 유일한 충돌은 프로세스를 중단하기 위해 put 호출을 만든 경우입니다.

putget은 결과 개체와 상호 작용할 때 동기식이므로 가장 먼저 수신되는 것이 먼저 완료됩니다. 우리는 결과 객체를 수정하지 않기 때문에 우리의 목적을 위해 프로세스 취소 요청을 무시할 수 있습니다. 고객이 보낸 순서와 동일한 순서로 접수 될 것이라는 보장은 없으며 시나리오에 실용적인 우려가 될 수도 있고 그렇지 않을 수도 있습니다.

나는, 서로 다른 프로세스에서 요청을 처리하기 위해 cluster를 사용한다면, 당신은 어쨌든 공유 객체를 통해 주위에 데이터를 전달 할 수 없을 것이라는 점을, (내 기억이 여기에 문제가있을 수 있지만) 그래서 복잡 믿을 그 가능성에 의해 추가 된 것은 이미 배제되어있다.

네트워크 성능 및 안정성의 차이가 유일한 실제 와일드 카드입니다. 서버는 요청을 들어오는 순서대로 처리하고 예상되는 결과를 제공합니다. 단일 고객 만있는 경우 이전 요청에서 다음 요청을 보낼 때까지 기다릴 수 있습니다. 그러면 성능이 다소 느려지지만 다소 방탄 당할 수 있습니다. 그렇지 않으면 요청을 보내고 걱정하지 마세요. 앱을 이미 취소 한 경우에도 & 두 번째 취소 요청을 처리 할 수있을 정도로 앱을 강력하게 만드십시오.

+0

Jason에게 감사드립니다. GET이 반환 할 객체의 현재 상태가 무엇이든간에 POST와 GET 사이에는 경쟁 조건이 없습니다. 이제는 POST가 "거의 완료"(단지'child.on ('close')'안에 들어 왔고 PUT이 동시에 발생하면 POST와 PUT에 동시에 처리가 취소 될 수 있습니다. , 비록 합법적으로 집행을 끝냈다. 이것을 피하기 위해 더 나은 약속이 주어 졌을까요? – Manali

+0

귀하의 요구 사항을 이해하지 않고는 답변을 드릴 수 없습니다 - 프로세스를 취소 할 수있는 "유효하지 않은"시간이 있습니까? 그렇다면 결과 객체에서 그 조건을 추적 할 필요가 있으며이를 검사하고 선택적으로 "실패"하여 취소해야합니다. 결과를'result.status = 'finishing'으로 변경하면됩니다. 즉,'child.on ('close')'가 실행되면 result.status == 'running'' 체크가 실패하게됩니다. 프로세스를 취소 할 수있는 무효 한 시간이 아닌 * 경우 * 합법적으로 완료 되더라도 취소 할 수 있다는 것을 받아 들여야합니다. – Jason

+0

아, 또한 on ('close') 이벤트와 put (put) 호출이 같은 프로세스에서 여전히 실행 중이기 때문에 여전히 "경쟁 조건"이 없습니다. - 'close' 호출이 먼저 발생하면' 먼저'put' 호출이 먼저 발생하면 먼저 완료됩니다. 그래서, 저의 첫 코멘트는 무의미합니다. – Jason

1

그냥 생각하지만 어쩌면 약속은 여기에 도움이 될 수 :이 경우 GET에

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); 
    } 
} 

child가 오류 또는 '가까이'이벤트에 의해 수행 된 경우에만 응답합니다.

+0

+1, 감사합니다. 약속을 사용하는 것은 재미있는 생각입니다. 내 요구 사항은 자식 프로세스가 실행 중일 때도 현재 결과를 반환해야하므로 자식 프로세스가 완료 될 때까지 기다리지 않으려한다는 것입니다. 또한 결과를 수정하는 PUT이 있습니다. – Manali

+0

또한이 솔루션에서 자식이 수행되지 않으면 어떻게됩니까? 클라이언트가 기다리고 있습니까? – Manali

+0

@Manali 예, 기다릴 것입니다. – dhilt

관련 문제