2011-12-22 3 views
7

웹 서버에서 실행되는 python 스크립트가 있습니다. main 함수가 호출되면 반환 할 때 몇 초간 잠자기 후 다시 호출됩니다. 사용자가 추가 한 새로운 업로드 동영상을 픽업하여 webm으로 변환하고 중간 프레임을 이미지와 다른 펑키 한 자료로 가져 오는 것이 목적입니다. ffmpeg에 외부 호출을 사용하고 있습니다. 아래 코드는 제가 어떻게 호출하는지 보여줍니다.상태를 확인하거나 파이썬으로 외부 프로세스를 죽이는 방법

duration = output[durationIndex+10:durationIndex+18] 
    durationBits = duration.split(":") 
    lengthInSeconds = (int(durationBits[0])*60*60) + (int(durationBits[1])*60) + (int(durationBits[2])) 

    child = subprocess.Popen(["ffmpeg","-y","-i",sourceVideo,"-f","mjpeg","-vframes","1","-ss",str(lengthInSeconds/2),destination], shell=True, stderr=subprocess.PIPE) 
    output = "" 
    while True: 
     out = child.stderr.read(1) 
     if out == '' and child.poll() != None: 
      break 
     if out != '': 
      output += out 

    updateSQL = "update `videos_graduatevideo` set thumbnail = '" + str(destination) + "' where `original_video` = '" + sourceVideo + "'" 
    cursor.execute(updateSQL) 

이 스크립트는 Windows 컴퓨터 atm에서 실행되고 있지만이 스크립트는 개발이 완료되면 유닉스 시스템에 배포 할 예정입니다.

문제가 있습니다. 계속 실행하려면이 python 스크립트가 필요합니다. ffmpeg에 문제가 생겨 스크립트가 중단되면 사용자가 업로드 한 비디오는 파이썬 스크립트를 찌를 때까지 "보류 중"상태로 유지됩니다. 나는 내가 가지고있는 특정 mov 파일이 ffmpeg를 무기한으로 기다리는 것을 안다. 프로세스가 실행 된 시간을 확인하고 너무 오래 실행 한 경우 프로세스를 종료 할 수 있습니까?

+1

정확히 똑같은 문제가있었습니다 (장고 대신 파이론을 사용했습니다). 필자는 데이타베이스 액세스 (장고 설정을 주면 모델을 사용할 수 있음)와 아약스 폴링 시스템을 사용하여 외부 프로그램을 작성하여 결과를 얻습니다. – JBernardo

+0

[셀러리] (http://celeryproject.org/)는 어떨까요? [모니터링] (http://celery.readthedocs.org/en/latest/userguide/monitoring.html)을 지원합니다. – danihp

답변

6

내가 아키텍처에 대한 MQ를 고려하면 도움이 될 것이라고 S. Lott의 의견에 동의하지만이 특정 문제에 대해서는 Popen을 사용하는 것이 좋습니다.

작성한 각 프로세스에 대해 생성 시간을 저장하십시오 (datetime.datetime.today()이면 충분합니다). 그리고 매분마다 열려있는 프로세스와 시간의 목록을 살펴보고 Popen.send_signal (signal), terminate() 또는 kill()을 사용해서는 안되는 것을 얻으십시오.

예 :

import time 
from subprocess import Popen 
from datetime import datetime 
jobs = [] 
max_life = 600 # in seconds 

def reap_jobs(jobs): 
    now = datetime.datetime.today() 
    for job in jobs: 
    if job[0] < now - datetime.timedelta(seconds=max_life) 
     job[1].kill() 
     # remove the job from the list if you want. 
     # but remember not to do it while iterating over the list 

for video in list_of_videos: 
    time = datetime.datetime.today() 
    job = Popen(...) 
    jobs.append((time,child)) 

while True: 
    reap_jobs(jobs) 
    time.sleep(60) 
-3

1 단계. CGI 스크립트를 사용하지 마십시오. 프레임 워크를 사용하십시오.

2 단계. 응답을 생성하는 함수에서 직접 서브 프로세스를 시작하지 마십시오. celery을 사용하십시오.

이 프로세스는 항상 서버에서 실행됩니다. 그것은 어떤 프레임 워크와도 독립적이며 django가 동일한 db로부터 읽습니다.

2 단계. 이 하위 프로세스를 항상 실행 상태로 두지 마십시오. Celery를 사용하여 요청이 도착하면 요청이 처리되고 요청을 처리 한 다음 중지합니다.

+0

당신은 당신의 대답에 많은 것을 생각했습니다. - 나는 장고를 사용하고 있지만이 프로세스는 항상 서버에서 실행 중입니다. 그것은 어떤 프레임 워크와도 독립적이며 django가 채우는 동일한 db로부터 읽습니다. - 응답이 생성되지 않고 완료되면 일부 db 필드가 채워집니다. – DrLazer

+0

@DrLazer : 질문에 대한 자세한 내용을 제공하지 않았기 때문에 제 답변에 많이 사용하고 있습니다. 모든 사실을 확인하기 위해 귀하의 질문에 ** 찬성하고 ** 업데이트 **하십시오. 답변에 대한 논평에서 사실을 은폐하는 것은 다른 사람들에게별로 도움이되지 않습니다. –

+1

나는 내가 묻고있는 질문을 다루기에 충분한 세부 사항을 제공한다. 나는 시스템에 대한 전체 스펙을 질문으로 쓰려고 거의하지 않는다. – DrLazer

0

하면 사용자가 지정한 프로세스를 모니터링 God - A Process Monitor를 살펴 보자하고 모니터링 조건에 따라 일부 작업을 수행합니다. 예를 들어, CPU 사용량에 눈을 유지하고 CPU 사용이 50 % 이상이면 프로세스를 다시 시작할 수 있습니다 : 실행중인 모든 프로세스 및 시스템에 대한 정보를 검색하기위한 인터페이스를 제공하는 파이썬 모듈이 있습니다

# code in Ruby 
# copyied from the documentation 
w.restart_if do |restart| 
    restart.condition(:cpu_usage) do |c| 
    c.above = 50.percent 
    c.times = 5 
    end 
end 
0

ps, top, df, kill, free, lsof, free, netstat, ifconfig, nice, ionice, iostato, iotop 등과 같은 명령 행 도구가 제공하는 많은 기능을 휴대용 방식으로 사용 (CPU, 디스크, 메모리) 가동 시간, tty : psutil. 도움이 될 것입니다.

1

제어 스크립트는 시스템을 시작한 스크립트이므로 시스템 리소스 사용이 아니라 시간에 따라 죽이기를 원하기 때문에 상당히 간단해야합니다. 다음은 수정 된 예제 코드입니다. 주석이있는 행을 찾으십시오.

import time 
timeout = 60 #child is allowed to run for 1 minute. 
duration = output[durationIndex+10:durationIndex+18] 
durationBits = duration.split(":") 
lengthInSeconds = (int(durationBits[0])*60*60) + (int(durationBits[1])*60) + (int(durationBits[2])) 

child = subprocess.Popen(["ffmpeg","-y","-i",sourceVideo,"-f","mjpeg","-vframes","1","-ss",str(lengthInSeconds/2),destination], shell=True, stderr=subprocess.PIPE) 
killtime = time.time() + timeout #timestamp after which the child process should be killed 
output = "" 
while True: 
    out = child.stderr.read(1) 
    if out == '' and child.poll() != None: 
     break 
    if out != '': 
     output += out 
    if time.time() > killtime: #check if 60 seconds have passed 
     child.kill() #tell the child to exit 
     raise RuntimeError("Child process still going %i seconds after launch" %killtime) #raise an exception so that updateSQL doesn't get executed 

updateSQL = "update `videos_graduatevideo` set thumbnail = '" + str(destination) + "' where `original_video` = '" + sourceVideo + "'" 
cursor.execute(updateSQL) 

당신은 다른 일에 RuntimeError에 변경하거나, 예외를 발생시키는 당신이 할 필요 밖의 무엇에 따라 대신 플래그를 설정있을 수 있습니다. child.kill() 행은 자식 프로세스가 죽는 원인이되지만 끝내기위한 가장 좋은 방법은 아닙니다. posix 시스템에 배포하는 경우 os.system ('kill -s 15 % i'% child.pid)을 대신 사용하여 좀 더 정상적으로 종료 할 수 있습니다.

관련 문제