2008-10-20 21 views
8

Tôi đã kế thừa ứng dụng django + fastcgi cần được sửa đổi để thực hiện tính toán dài (lên đến nửa giờ hoặc hơn). Những gì tôi muốn làm là chạy tính toán trong nền và trả về một "công việc của bạn đã được bắt đầu" -type phản ứng. Trong khi quá trình đang chạy, các lượt truy cập tiếp theo đến url sẽ trả về "công việc của bạn vẫn đang chạy" cho đến khi công việc kết thúc tại thời điểm đó kết quả của công việc sẽ được trả lại. Mọi lần truy cập tiếp theo trên url sẽ trả về kết quả được lưu trong bộ nhớ cache.django, fastcgi: làm thế nào để quản lý một quá trình chạy dài?

Tôi là một người mới hoàn toàn ở django và chưa thực hiện bất kỳ công việc web quan trọng nào trong một thập kỷ vì vậy tôi không biết nếu có cách tích hợp để thực hiện những gì tôi muốn. Tôi đã cố gắng bắt đầu quá trình thông qua subprocess.Popen(), và điều đó hoạt động tốt ngoại trừ thực tế nó để lại một mục không tồn tại trong bảng quá trình. Tôi cần một giải pháp sạch có thể xóa các tệp tạm thời và mọi dấu vết của quá trình khi nó đã hoàn tất.

Tôi cũng đã thử nghiệm với fork() và luồng và chưa đưa ra giải pháp khả thi. Có một giải pháp kinh điển cho những gì dường như với tôi là một trường hợp sử dụng khá phổ biến? FWIW này sẽ chỉ được sử dụng trên một máy chủ nội bộ với lưu lượng truy cập rất thấp.

+0

Vui lòng cung cấp mã bạn đang làm để sinh ra quá trình xử lý nền. Có rất nhiều cách để làm điều này, bạn đang sử dụng cái nào? –

Trả lời

3

Có thể bạn có thể xem xét vấn đề theo cách khác.

Có thể bạn có thể thử DjangoQueueService và có "daemon" nghe hàng đợi, xem liệu có gì mới và xử lý nó không.

+0

Đó chắc chắn là gần với những gì tôi đang tìm kiếm. Tôi stumbled khi đó trước đó nhưng tôi hy vọng sẽ tìm thấy một giải pháp mà không yêu cầu tôi để thêm bất kỳ phụ thuộc bổ sung. Cảm ơn. –

+0

Bạn có thể cuộn hệ thống xếp hàng của riêng bạn sau đó. Ý tôi là, nó không phải là rất khó khăn để làm. – changelog

+0

là tác giả của Dịch vụ xếp hàng Django, tôi muốn nói về hướng cần tây hoặc một trong những dịch vụ xếp hàng đó thay thế. Đó là một hack gọn gàng vào ban ngày, nhưng đã dễ dàng bị vượt qua bây giờ. – heckj

4

Tôi phải giải quyết vấn đề tương tự ngay bây giờ. Nó sẽ không phải là một trang web công cộng, nhưng tương tự, một máy chủ nội bộ với lưu lượng truy cập thấp.

trở ngại kỹ thuật:

  • tất cả các dữ liệu đầu vào cho quá trình chạy dài có thể được cung cấp trên bắt đầu của nó
  • quá trình chạy dài không yêu cầu tương tác người dùng (trừ đầu vào ban đầu để bắt đầu một quá trình)
  • thời gian tính toán đủ dài để kết quả không thể được phục vụ cho khách hàng trong phản hồi HTTP ngay lập tức
  • một số loại phản hồi (loại thanh tiến trình) từ quy trình chạy dài.

Do đó, chúng tôi cần ít nhất hai "lượt xem" trên web: một để bắt đầu quá trình chạy dài và quy trình còn lại để theo dõi trạng thái/thu thập kết quả.

Chúng ta cũng cần một số loại thông tin liên lạc interprocess: gửi dữ liệu người dùng từ khởi (web server theo yêu cầu http) đến quá trình chạy dài, và sau đó gửi kết quả của nó đến reciever (một lần nữa web máy chủ, được thúc đẩy bởi các yêu cầu http). Trước đây là dễ dàng, sau này là ít rõ ràng. Không giống như trong lập trình unix bình thường, người nhận không được biết ban đầu. Người nhận có thể là một quá trình khác với người khởi xướng, và nó có thể bắt đầu khi công việc chạy dài vẫn đang được tiến hành hoặc đã kết thúc. Vì vậy, các đường ống không hoạt động và chúng tôi cần một số tính thấm của kết quả của quá trình chạy dài.

tôi thấy hai giải pháp khả thi:

  • ra mắt công văn của các quá trình chạy dài để quản lý công việc chạy dài (điều này có lẽ là django-queue-dịch vụ nêu trên là những gì);
  • lưu kết quả vĩnh viễn, trong tệp hoặc trong DB.

Tôi thích sử dụng tệp tạm thời và nhớ vị trí của chúng trong dữ liệu phiên. Tôi không nghĩ rằng nó có thể được thực hiện đơn giản hơn.

Một kịch bản công việc (đây là quá trình chạy dài), myjob.py:

import sys 
from time import sleep 

i = 0 
while i < 1000: 
    print 'myjob:', i 
    i=i+1 
    sleep(0.1) 
    sys.stdout.flush() 

django urls.py lập bản đồ:

urlpatterns = patterns('', 
(r'^startjob/$', 'mysite.myapp.views.startjob'), 
(r'^showjob/$', 'mysite.myapp.views.showjob'), 
(r'^rmjob/$', 'mysite.myapp.views.rmjob'), 
) 

xem django:

from tempfile import mkstemp 
from os import fdopen,unlink,kill 
from subprocess import Popen 
import signal 

def startjob(request): 
    """Start a new long running process unless already started.""" 
    if not request.session.has_key('job'): 
      # create a temporary file to save the resuls 
      outfd,outname=mkstemp() 
      request.session['jobfile']=outname 
      outfile=fdopen(outfd,'a+') 
      proc=Popen("python myjob.py",shell=True,stdout=outfile) 
      # remember pid to terminate the job later 
      request.session['job']=proc.pid 
    return HttpResponse('A <a href="/showjob/">new job</a> has started.') 

def showjob(request): 
    """Show the last result of the running job.""" 
    if not request.session.has_key('job'): 
      return HttpResponse('Not running a job.'+\ 
       '<a href="/startjob/">Start a new one?</a>') 
    else: 
      filename=request.session['jobfile'] 
      results=open(filename) 
      lines=results.readlines() 
      try: 
       return HttpResponse(lines[-1]+\ 
         '<p><a href="/rmjob/">Terminate?</a>') 
      except: 
       return HttpResponse('No results yet.'+\ 
         '<p><a href="/rmjob/">Terminate?</a>') 
    return response 

def rmjob(request): 
    """Terminate the runining job.""" 
    if request.session.has_key('job'): 
      job=request.session['job'] 
      filename=request.session['jobfile'] 
      try: 
       kill(job,signal.SIGKILL) # unix only 
       unlink(filename) 
      except OSError, e: 
       pass # probably the job has finished already 
      del request.session['job'] 
      del request.session['jobfile'] 
    return HttpResponseRedirect('/startjob/') # start a new one 
Các vấn đề liên quan