2017-11-01 8 views
0

기술적으로 다른 비동기 파이썬 하위 프로세스를 생성하는 파이썬 하위 프로세스를 생성하지만 제목이 이미 길었습니다. Node/ExpressJS는 첫 번째 Python 하위 프로세스가 성공적으로 실행되었는지 확인하기 위해 대기해야하지만 하위 프로세스는 완료되지 않으므로 완료하는 데 몇 분이 걸릴 수 있습니다. 그러나 겉보기에 올바른 설정을 했음에도 불구하고 브라우저를 통해 API 요청을하면 하위 프로세스의 하위 프로세스를 기다리는 중 끊어지는 것처럼 보입니다.비동기 파이썬 하위 프로세스를 생성하는 노드/익스프레스 API 만들기

는 배경 :

여기에 기본 목표는 다음 출력을 얻을 모델을 실행하는 데 사용할 수있는 노드/ExpressJS 기반 API를 만드는 것입니다. 모델을 실행하는 데 몇 분이 걸릴 수 있으므로 한 번의 API 요청으로 응답을 기다리는 대신 내 전략은 요청을 두 개로 분할하는 것입니다. 하나는 모델을 준비/실행하고 두 번째는 결과를 검색하는 것입니다.

prep 통화는 모델을 시작하고 userid에 의한 점검 등을 통해 언제든지 한 모델에 대해서만 실행이 활성화되도록 할 수 있습니다. 모델 실행이 성공적으로 시작되었거나 현재 실행 중이므로 새 실행을 시작할 수 없다는 메시지를 반환합니다.

검색 호출은 데이터 검색을 시도합니다. 출력이 계속 실행 중임을 나타내는 메시지, 실행이 실패한 경우 오류 또는 모델 실행이 완료되면 통계와 숫자 및 기타 등등을 반환 할 수 있습니다.

문제 :

문제는 준비 통화에 있습니다. Node/Express는 prep.py 스크립트를 호출합니다. prep.py 스크립트는 다른 하위 프로세스 (run.py)를 생성하지만 Node/Express 또는 prep.py는 해당 하위 프로세스가 완료 될 때까지 대기하지 않아야합니다. 그렇지 않으면 REST API를 호출하면 모델이 완료 될 때까지 기다릴 수 있습니다.

sp = subprocess.Popen([ 
    "python", 
    os.path.join(this_dir, "run.py"), 
    userid, 
    processid 
]) 

print json.dumps({'response': 'success'}) 
# end of script 

명령 행 (즉, CMD)를 통해이 실행이 잘 작동 다음과 같이

그래서이 파이썬에서 수행되는 방식이다. 나는 prep.py를 호출하고 즉시 JSON을 덤프하고 CMD는 다른 입력/명령에 대한 준비가되었습니다. 작업 관리자에서 파이썬이 백그라운드에서 실행되고 결국 모델 출력 파일이 필요할 때 나타납니다.

그러나 브라우저를 통해 Node/ExpressJS를 통해 호출 할 때 API는 run.py가 완료 될 때까지 기다리는 것처럼 계속 작동합니다. (결과적으로 타임 아웃되고 브라우저가 자동으로 새로 고쳐지고 페이지에 "오류가 발생했습니다. 모델이 이미 실행 중입니다."- 스팸 방지 모델 작업을 방지하기위한 장애 조치 작업을 확인하는 것이 좋습니다.)

여기 API의 준비 호출이되는 통해 경로입니다 :

router.route('/prep/:userid/:key') 
    .get(throttle(tOptions), function(req, res, next) { 
     var error = null; 
     RunPy(
      // path to script 
      path.join(process.env.PYSCRIPTDIR, "prep.py"), 
      // parameters/arguments 
      [req.params.userid, req.params.key], 
      // on complete callback 
      function(ret) { 
       if(error) { 
        next({message: error}); 
       } else { 
        res.send(ret); 
       } 
      }, 
      // on error callback 
      function(err) { error = getPythonError(err); } 
     ); 
    }); 

RunPy 단지 파이썬 하위 프로세스 실행 할 수있는 편리한 래퍼 인 :

const spawn = require("child_process").spawn; 

module.exports = function(pyPath, args, onComplete, onError, onData) { 
    var py = spawn('python', [pyPath].concat(args)); 
    var ret = ""; 
    py.stdout.on('data', function(data) { 
     ret += data.toString(); 
     if(onData) onData(data.toString()); 
    }); 
    py.stderr.on('data', function(data) { 
     onError(data.toString()); 
    }); 
    py.stdout.on('end', function() { 
     onComplete(ret); 
    }) 
}; 

나는 아마 파이썬 스크립트를 보장 할 수 만 출력 번 에 대한 완전한 콜백 발사가 있습니다. 첫 번째 py.stdout.on('data', ..)하지만 그게 멋져 보이지 않고 몇 분이 걸리는이 python 스크립트를 기다리는 매달려있는 자바 스크립트 스레드를 그냥 놓는 아이디어가 마음에 들지 않습니다.

답변

0

그래서 내가 생각한 한 가지 작업은 약간 짜증이났다. 어쩌면 더 나은 대답이 나타날 것입니다.

기본적으로 preprep.py (더 나은 이름 필요)를 작성합니다. Node/Express가 대기해야하는 작업 (예 : 모델이 사용자에 대해 이미 현재 실행 중인지 확인)을 수행합니다. 그것은 모델을 시작하지 않습니다. 실행하지 않는 것이 모두 확실하거나 그렇지 않은 경우 예외를 발생시키는 경우 'true'를 반환합니다. 그런 다음 Node/Express는 prep.py를 실행하고 응답을 기다리지 않거나 돌보지 않으며 성공적으로 시작되고 계속 진행되는 것으로 가정합니다.

router.route('/prep/:userid/:key') 
    .get(throttle(tOptions), function(req, res, next) { 
     var error = null; 
     var onError = function(err) { error = getPythonError(err); } 
     // on complete callback with a nested RunPy call 
     var onComplete = function(ret) { 
      if(error) { 
       // error handling same as before 
       next({message: error}); 
      } else if(ret.replace(/^\s+|\s+$/g, '').toLowerCase() === "true") { 
       // if response (stripped of whitespace and lowercase) is true send success response 
       res.send({response: "success"}); 
       // run prep.py with no callbacks 
       RunPy(path.join(process.env.PYSCRIPTDIR, "prep.py"), [req.params.userid]); 
      } else { 
       // just for completeness 
       res.send({response: "could not start model"}); 
      } 
     }; 
     RunPy(
      path.join(process.env.PYSCRIPTDIR, "preprep.py"), 
      [req.params.userid, req.params.key], 
      onComplete, 
      onError 
     ); 
    }); 

RunPy가 약간 수정되었으므로 모든 콜백은 선택 사항입니다.

0

설치가 잘된 것 같아서 작은 세부 사항과 혼동을 느낀 것 같습니다.

응답을 '분 길이 프로세스 초기화'와 '데이터를 사용할 수 있음'의 두 부분으로 나눠야한다는 점을 올바르게 지적하십시오. 그러나 실제 코드에서이 둘을 하나로 모으고, 익스프레스 서버는 파이썬 스크립트가 완료되기 전에 아무것도 반환하지 않습니다.

걸려있는 것은 서버가 아니라 몇 분 동안 아무 것도받지 못해 잠시 후에 시간이 초과되는 클라이언트 인 클라이언트입니다.

따라서 이상적으로 서버는 클라이언트에게 '대기 모드'로 들어가는 내용을 즉시 반환해야합니다. 그런 다음 클라이언트가 결과를 사용할 수있는시기를 파악하는 방법에 대해 생각할 수 있습니다.

+0

subprocess.Popen의 작동 방식을 잘못 이해했을 수도 있지만 호출 한 스크립트가 대기 할 필요가없는 비동기 프로세스가 발생한다고 생각했습니다. 적어도 CMD에서이를 실행하면 { "response": "success"} (Express가 반환해야하는 것)을 인쇄하고 새 명령에 대한 터미널을 즉시 재설정합니다. [아, 오타가 있었는데 원래의 게시물에 "인쇄"명령을 추가했습니다] – wowohweewah