Python Webserver: как обслуживать запросы асинхронно - PullRequest
3 голосов
/ 12 февраля 2011

Мне нужно создать промежуточное программное обеспечение Python, которое будет выполнять следующие действия:

a) Принимать запросы http get / post от нескольких клиентов.

b) Изменить и отправить эти запросы бэкэнд-удаленному приложению (через сокетную связь). У меня нет никакого контроля над этим удаленным приложением.

в) Получать обработанные результаты из внутреннего приложения и возвращать эти результаты запрашивающим клиентам.

Теперь клиенты ожидают синхронного сценария запроса / ответа. Но внутреннее приложение не возвращает результаты синхронно. То есть некоторые запросы обрабатываются намного дольше, чем другие. Следовательно,

Клиент 1: отправить http запрос C1 -> получить ответ R1

Клиент 2: отправить запрос http C2 -> получить ответ R2

Клиент 3: отправить http запрос C3 -> получить ответ R3

Промежуточное программное обеспечение Python получает их в некотором порядке: C2, C3, C1. Отправляет их в этом порядке на сервер (как сообщения не из http). Backend отвечает результатами в смешанном порядке R1, R3, R2. Промежуточное программное обеспечение Python должно упаковать эти ответы обратно в объекты ответа http и отправить ответ обратно соответствующему клиенту.

Есть ли пример кода для программирования такого рода поведения. Кажется, что-то вроде 20 различных веб-фреймворков для Python, и я не понимаю, какой из них лучше всего подойдет для этого сценария (предпочел бы что-то настолько легкое, насколько это возможно ... Я бы посчитал Django слишком тяжелым ... Я попробовал бутылку , но я не уверен, как идти о программировании, что для этого сценария).

=============================================== = * * тысяча двадцать-один

Обновление (на основе обсуждений ниже): у запросов есть идентификатор запроса. Ответы имеют идентификатор ответа (который должен соответствовать идентификатору запроса, которому они соответствуют). Между промежуточным программным обеспечением и удаленным бэкэнд-приложением имеется только одно сокетное соединение. Хотя мы можем поддерживать словарь {request_id: ip_address}, проблема заключается в том, как создать объект ответа HTTP для правильного клиента. Я предполагаю, что многопоточность может решить эту проблему, когда каждый поток поддерживает свой собственный объект ответа.

Ответы [ 2 ]

3 голосов
/ 21 августа 2011

Винтовые рамки. Это именно такая задача для asyncore . Этот модуль позволяет основывать на событиях сетевое программирование: при наличии набора сокетов он вызывает указанные обработчики, когда данные готовы по любому из них. Таким образом, потокам нет необходимости просто тупо ждать поступления данных на одном сокете и мучительно передавать их другому потоку. Вы должны были бы самостоятельно реализовать обработку http, но примеры можно найти по этому поводу. В качестве альтернативы, вы можете использовать асинхронную функцию uwsgi , которая позволит интегрировать ваше приложение с существующим веб-сервером, но по умолчанию не интегрируется с асинхронным, хотя это не составит труда сделай так, чтоб это работало. Зависит от конкретных потребностей.

2 голосов
/ 13 февраля 2011

Цитирую ваш комментарий:

Промежуточное программное обеспечение использует одно постоянное сокетное соединение с серверной частью. Все запросы от промежуточного программного обеспечения направляются через этот единственный сокет. Клиенты отправляют идентификатор запроса вместе со своими запросами. Идентификатор ответа должен соответствовать идентификатору запроса. Таким образом, остается вопрос: как промежуточное программное обеспечение (веб-сервер) отслеживает, какой идентификатор запроса принадлежал какому клиенту? Я имею в виду, есть ли какой-нибудь способ для сценария cgi в промежуточном программном обеспечении создать БД из кортежей типа и, когда идентификатор ответа совпадает, а затем отправить http-ответ на clientip: clienttcpport?

Есть ли какая-либо особая причина для выполнения всей этой обработки в промежуточном программном обеспечении? Вы должны быть в состоянии сделать все это в декораторе или в другом месте, если это более уместно.

В любом случае вам необходимо поддерживать глобальный параллельный словарь (расширить dict и защитить его с помощью threading.Lock). По новому запросу сохраните данный идентификатор запроса как ключ и свяжите его с соответствующим клиентом (отправителем). Всякий раз, когда ваш сервер отвечает, извлеките клиента из этого словаря и удалите запись, чтобы она не накапливалась вечно.

ОБНОВЛЕНИЕ : кто-то уже расширил словарь для вас - отметьте этот ответ .

...