2011-12-22 10 views
7

Tôi có một tập lệnh python chạy trên máy chủ web của tôi. Chức năng chính được gọi sau đó khi nó trả về nó chỉ ngủ trong vài giây và được gọi lại. Mục đích của nó là chọn bất kỳ video tải lên mới nào mà người dùng đã thêm và chuyển đổi chúng thành webm, kéo khung giữa làm hình ảnh và một loạt các nội dung thú vị khác. Tôi đang sử dụng một cuộc gọi bên ngoài để ffmpeg. Đoạn mã dưới đây cho thấy cách tôi gọi nó.Làm thế nào để bạn kiểm tra trạng thái hoặc giết một quá trình bên ngoài với python

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) 

Tập lệnh này chạy trên máy tính Windows nhưng có lẽ tôi sẽ triển khai nó trên hệ thống Unix khi hoàn tất.

Vấn đề là. Tôi cần tập lệnh python này để tiếp tục chạy. Nếu có sự cố với ffmpeg và tập lệnh của tôi bị treo, video do người dùng tải lên sẽ chỉ ở trạng thái "đang chờ xử lý" cho đến khi tôi đọc kịch bản lệnh python. Tôi biết một tập tin mov nhất định tôi đã làm cho ffmpeg treo không chính xác. Có someway tôi có thể kiểm tra bao lâu một quá trình đã được chạy và sau đó giết nó đi nếu nó đã được chạy quá lâu?

+1

Tôi đã có cùng một vấn đề chính xác (tôi đã sử dụng giá treo thay vì Django). Tôi đã viết một chương trình bên ngoài với truy cập cơ sở dữ liệu (nếu bạn đặt cho nó cài đặt Django, bạn có thể sử dụng các mô hình của bạn) và một hệ thống bỏ phiếu ajax để có được kết quả. – JBernardo

+0

Còn về [cần tây] (http://celeryproject.org/). Có hỗ trợ [giám sát] (http://celery.readthedocs.org/en/latest/userguide/monitoring.html). – danihp

Trả lời

6

Tôi đồng ý với S. Lott ở chỗ có vẻ như bạn sẽ được hưởng lợi từ việc xem xét MQ cho kiến ​​trúc của bạn, nhưng đối với vấn đề cụ thể này tôi nghĩ việc bạn sử dụng Popen là OK.

Đối với mỗi quá trình bạn tạo, lưu thời gian tạo (ví dụ như datetime.datetime.today() sẽ đủ). Sau đó, mỗi phút hoặc lâu hơn đi qua danh sách các quá trình mở và thời gian và gặt hái những cái mà không nên có bằng cách sử dụng Popen.send_signal (tín hiệu), chấm dứt(), hoặc kill().

Ví dụ:

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

Bước 1. Không sử dụng tập lệnh CGI. Sử dụng một khung công tác.

Bước 2. Không khởi động tiến trình con trực tiếp trong hàm tạo phản hồi. Sử dụng celery.

quá trình này chỉ chạy trên máy chủ mọi lúc. Nó độc lập với mọi khung công tác và đọc từ cùng một db mà django điền vào

Bước 2, một lần nữa. Đừng để tiến trình con này chạy mọi lúc. Sử dụng Celery để nó được bắt đầu khi một yêu cầu đến, xử lý yêu cầu đó (và chỉ yêu cầu đó) và sau đó dừng lại.

+0

Bạn đã giả định rất nhiều trong câu trả lời của mình. - Tôi đang sử dụng django, nhưng quá trình này chỉ chạy trên máy chủ mọi lúc. Nó độc lập với mọi framework và đọc từ cùng một db mà django populates. - Không có phản hồi nào được tạo, nó chỉ điền vào một số trường db khi nó được thực hiện – DrLazer

+0

@DrLazer: Tôi giả định rất nhiều trong câu trả lời của tôi vì bạn không cung cấp nhiều chi tiết trong câu hỏi của bạn. Làm tất cả chúng ta một ưu tiên và ** cập nhật ** câu hỏi của bạn để có tất cả các sự kiện. Che giấu sự thật trong một bình luận cho một câu trả lời không phải là vô cùng hữu ích cho người khác. –

+1

Tôi cung cấp đủ chi tiết để trả lời câu hỏi tôi đang hỏi. Tôi hầu như không viết toàn bộ thông số cho hệ thống trong một câu hỏi. – DrLazer

0

Hãy xem God - A Process Monitor luôn theo dõi quá trình bạn chỉ định, và thực hiện một số hành động theo điều kiện giám sát của bạn. Ví dụ, nó có thể giữ một mắt trên việc sử dụng cpu và khởi động lại quá trình này nếu sử dụng cpu là trên 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

Có một mô-đun python mà cung cấp một giao diện để lấy thông tin về tất cả các tiến trình đang chạy và hệ thống sử dụng (CPU, đĩa, bộ nhớ) theo cách di động, triển khai nhiều chức năng được cung cấp bởi các công cụ dòng lệnh như: ps, top, df, kill, miễn phí, lsof, miễn phí, netstat, ifconfig, nice, ionice, iostato, iotop, thời gian hoạt động, tty: psutil. Nó sẽ giúp.

1

Vì tập lệnh điều khiển là tập lệnh bắt đầu, và vì bạn muốn nó bị giết dựa trên thời gian chứ không phải hệ thống sử dụng tài nguyên hệ thống, nên nó khá đơn giản. Dưới đây là mã ví dụ của bạn với một số sửa đổi; tìm các dòng có nhận xét.

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) 

Bạn có thể thay đổi RuntimeError thành một thứ khác hoặc đặt cờ thay vì đặt ngoại lệ, tùy thuộc vào việc bạn cần làm gì khác. Dòng child.kill() sẽ khiến quá trình con chết, nhưng nó có thể không phải là cách duyên dáng nhất để kết thúc nó. Nếu bạn triển khai nó trên một hệ thống posix, bạn có thể sử dụng os.system ('kill -s 15% i'% child.pid) để thay thế nó một cách duyên dáng hơn.