django, fastcgi: как справиться с длительным процессом?

Итак, вы хотите написать характеристику, которая будет выполнять проверку, чтобы увидеть, была ли модель обновлена ​​с момента получения текущей, и отбросить что-то, что вы можете зацепить, чтобы уведомить пользователя? Я хотел бы изучить создание базовой модели, которую расширяют все ваши модели, и использование событий модели в этой базовой модели. Возможно, вам даже не понадобится черта, если у вас есть все модели, расширяющие базовую модель. См. Ниже пример метода события модели:

protected static function boot(){
    parent::boot();
    static::saving(function($thisModel){
        $changes = Model::where('version', $thisModel->version)
            ->where('id', $thisModel->id)->first()
        /** if changes->version matches this one, good, if not, set some
         *  property on the model that can be checked.   
         */
    }
}

Это произойдет , когда модель будет сохранена, и если вы return false; окажетесь в любой точке метода, сохранение завершится неудачно, и модель не будет сохранена.

Если вы все еще хотите использовать черту, убедитесь, что метод загрузки соответствует следующему формату: bootTraitName (), иначе он не загрузится при загрузке реализующих классов. Это сложный вопрос с множеством разных точек зрения, но я надеюсь, что по крайней мере дал вам кое-что рассмотреть.

Редактировать: я никогда не использовал модельные события в базовой модели, поэтому я не уверен, что parent::boot(); необходимо. Возможно, придется проверить.

8
задан 20 October 2008 в 18:05
поделиться

2 ответа

Я должен решить подобную проблему теперь. Это не будет общедоступным сайтом, но точно так же внутренним сервером с низким трафиком.

Технические ограничения:

  • все входные данные к длительному процессу могут быть предоставлены на его запуске
  • длительный процесс не требует взаимодействия с пользователем (за исключением входа начальной буквы для запуска процесса)
  • время вычисления достаточно долго так, чтобы результаты не могли быть поданы клиенту в непосредственном ответе HTTP
  • своего рода обратная связь (вид индикатора выполнения) от длительного процесса требуется.

Следовательно, нам нужны по крайней мере две сети “представления”: один, чтобы инициировать длительный процесс и другой, контролировать его состояние/собирать результаты.

Нам также нужно своего рода межпроцессное взаимодействие: отправьте пользовательские данные от инициатора (веб-сервер на запросе HTTP) к длительному процессу и затем отправьте его результаты на получатель (снова веб-сервер, управляемый запросами HTTP). Первый легок, последний менее очевиден. В отличие от этого, в нормальном программировании Unix, получатель не известен первоначально. Получатель может быть другим процессом от инициатора, и он может запуститься, когда длительное задание все еще происходит или уже закончено. Таким образом, каналы не работают, и нам нужно некоторое постоянство результатов длительного процесса.

Я вижу два возможных решения:

  • запуски отправки длительных процессов к длительному диспетчеру заданий (это, вероятно, что вышеупомянутый django-queue-service);
  • сохраните результаты постоянно, или в файле или в DB.

Я предпочел использовать временные файлы и помнить их locaiton в данных сессии. Я не думаю, что это может быть сделано более простым.

Сценарий задания (это - длительный процесс), 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 отображение:

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

представления 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
4
ответ дан 5 December 2019 в 21:23
поделиться

Возможно, Вы могли посмотреть на проблему наоборот.

Возможно, Вы могли попробовать DjangoQueueService и иметь "демона", слушающего очередь, видя, существует ли что-то новое, и обработайте его.

3
ответ дан 5 December 2019 в 21:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: