асинхронное выполнение задач для веб-приложения

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

Конечно, эти задачи могут занимать много времени, поэтому сервер не должен зависать для завершения выполнения скриптов до отправки ответа клиенту. Поэтому мне нужно выполнить асинхронное выполнение сценариев и дать клиенту «ресурс здесь, но не готов» и, возможно, сообщить ему конечную точку ajax для опроса, чтобы он мог получить и отобразить ресурс, когда готов.

Теперь мой вопрос не относится к дизайну (хотя мне бы очень понравились любые намеки на этот счет). Мой вопрос: существует ли уже система для решения этой проблемы, чтобы я не изобретал квадратное колесо? Если бы мне пришлось, я бы использовал диспетчер очередей процессов, чтобы отправить задачу и поставить конечную точку HTTP, чтобы снимать статус, что-то вроде «ожидание», «прервано», «завершено» для клиента ajax, но если что-то подобное уже существует специально для этой задачи, мне бы это больше всего понравилось.

Я работаю на питоне+джанго.

Изменить. Обратите внимание, что основная проблема заключается не в том, как сервер и клиент должны согласовывать и обмениваться информацией о статусе задачи.

Проблема в том, как сервер обрабатывает отправку и постановку в очередь очень длинных задач. Другими словами, мне нужна система получше, чем если бы мой сервер отправлял скрипты на LSF. . Не то чтобы это не сработало, но я думаю, что это слишком...

Редактировать 2: я добавил награду, чтобы посмотреть, смогу ли я получить другой ответ. Я проверил pyprocessing, но не могу выполнить отправку задания и повторно подключиться к очереди на более позднем этапе.


person Stefano Borini    schedule 17.11.2009    source источник


Ответы (7)


Здесь вам не следует изобретать велосипед.

Посетите gearman. Он имеет библиотеки на многих языках (включая Python) и довольно популярен. Не уверен, что у кого-нибудь есть готовые способы легко подключить django к вызовам gearman и ajax, но это не должно быть сложным, чтобы сделать эту часть самостоятельно.

Основная идея заключается в том, что вы запускаете сервер заданий gearman (или несколько серверов заданий), ваш веб-запрос ставит задание в очередь (например, «resize_photo») с некоторыми аргументами (например, «{photo_id: 1234}»). Вы ставите это в очередь как фоновую задачу. Вы получаете ручку обратно. Затем ваш запрос ajax будет опрашивать это значение дескриптора, пока он не будет помечен как завершенный.

Затем у вас есть рабочий (или, возможно, многие), который представляет собой отдельный процесс Python, подключающийся к этому серверу заданий, регистрируется для заданий «resize_photo», выполняет работу и затем помечает ее как завершенную.

Я также нашел этот сообщение в блоге, в котором довольно хорошо резюмируется его использование. .

person rhettg    schedule 02.12.2009
comment
Похоже, он делает именно то, что мне нужно. Спасибо - person Stefano Borini; 02.12.2009
comment
Хороший! Похоже, полезный фреймворк для использования в будущем. Прохладный! - person Hugh Perkins; 03.12.2009

Вы можете попробовать два подхода:

  • Чтобы вызывать веб-сервер каждые n интервалов и сообщать идентификатор задания; серверные процессы и возвращают некоторую информацию о текущем выполнении этой задачи
  • Чтобы реализовать долго работающую страницу, отправка данных каждые n интервалов; для клиента этот HTTP-запрос «всегда» будет "loading", и ему необходимо собирать новую информацию каждый раз, когда получен новый фрагмент данных.

О втором варианте вы можете узнать больше, прочитав о Comet; Используя ASP.NET, вы можете сделать нечто подобное, реализуя System. Интерфейс Web.IHttpAsyncHandler.

person Rubens Farias    schedule 17.11.2009
comment
не моя проблема. моя проблема заключается в том, чтобы отправлять данные на стороне сервера из серверного приложения. Другими словами Сервер‹-1-›Веб-интерфейс‹-2-›клиент Ajax решает мне 2, а не 1. - person Stefano Borini; 17.11.2009
comment
Нет, я уточняю вопрос, секундочку - person Stefano Borini; 17.11.2009

Я не знаю системы, которая это делает, но было бы довольно легко реализовать свою собственную систему:

  • create a database table with jobid, jobparameters, jobresult
    • jobresult is a string that will hold a pickle of the result
    • jobparameters — это маринованный список входных аргументов
  • когда сервер начинает работать над заданием, он создает новую строку в таблице и запускает новый процесс для ее обработки, передавая этому процессу идентификатор задания.
  • процесс обработчика задач обновляет результат задания в таблице после завершения
  • a webpage (xmlrpc or whatever you are using) contains a method 'getResult(jobid)' that will check the table for a jobresult
    • if it finds a result, it returns the result, and deletes the row from the table
    • в противном случае он возвращает пустой список, или None, или предпочитаемое вами возвращаемое значение, сигнализирующее о том, что задание еще не завершено.

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

person Hugh Perkins    schedule 30.11.2009

Во-первых, вам нужен какой-то отдельный "рабочий" сервис, который будет запускаться отдельно при включении питания и связываться с обработчиками http-запросов через некий локальный IPC, например UNIX-сокет (быстрый) или базу данных (простой).

Во время обработки запроса cgi запрашивает у рабочего состояния или другие данные и воспроизводит их клиенту.

person vitaly.v.ch    schedule 01.12.2009

Вы можете сообщить, что ресурс «обрабатывается», ответив HTTP-кодом 202: клиентская сторона должна будет повторить попытку позже, чтобы получить завершенный ресурс. В зависимости от случая вам, возможно, придется выдать «идентификатор запроса», чтобы сопоставить запрос с ответом.

В качестве альтернативы вы можете взглянуть на существующие библиотеки COMET, которые могут удовлетворить ваши потребности более «из коробки». Я не уверен, есть ли какие-либо, которые соответствуют вашему текущему дизайну Django.

person jldupont    schedule 17.11.2009

Вероятно, это не лучший ответ для решения python/django, с которым вы работаете, но мы используем Microsoft Message Queue для подобных вещей. Это в основном работает так

  1. Веб-сайт обновляет строку базы данных где-то со статусом «Обработка».
  2. Веб-сайт отправляет сообщение в MSMQ (это неблокирующий вызов, поэтому он сразу же возвращает управление веб-сайту)
  3. Служба Windows (на самом деле это может быть любая программа) «наблюдает» за MSMQ и получает сообщение
  4. Служба Windows обновляет строку базы данных со статусом «Готово».

В любом случае это суть. Это было довольно надежно для нас и действительно легко масштабировалось и управлялось.

-al

person Al W    schedule 02.12.2009

Еще один хороший вариант для python и django — Celery.

И если вы считаете, что Celery слишком тяжел для ваших нужд, вы можете взглянуть на простую распределенную taskqueue.

person versale    schedule 18.02.2012