Как обслуживать несколько запросов параллельно с витой Кляйн - PullRequest
0 голосов
/ 27 января 2019

Я создаю API для выполнения команд командной строки.На сервере есть только два метода: «запустить» и «остановить».Итак, основная функция «run» - запускать программу командной строки на стороне сервера и возвращать список с системным выводом.С другой стороны, функция «стоп» просто убивает запущенный процесс.Вот код:

import sys
import json
import subprocess

from klein import Klein


class ItemStore(object):
    app = Klein()
    current_process = None

    def __init__(self):
        self._items = {}

    def create_process(self, exe):
        """
        Run command and return the system output inside a JSON string
        """
        print("COMMAND: ", exe)
        process = subprocess.Popen(exe, shell=True, stdout=subprocess.PIPE,
                                   stderr=subprocess.STDOUT)
        self.current_process = process

        # Poll process for new output until finished
        output_lines = []

        counter = 0
        while True:
            counter = counter + 1
            nextline = process.stdout.readline()

            if process.poll() is not None:
                break

            aux = nextline.decode("utf-8")

            output_lines.append(aux)
            sys.stdout.flush()
            counter = counter + 1

        print("RETURN CODE: ", process.returncode)
        return json.dumps(output_lines)

    @app.route('/run/<command>', methods=['POST'])
    def run(self, request, command):
        """
        Execute command line process
        """
        exe = command
        print("COMMAND: ", exe)

        output_lines = self.create_process(exe)

        request.setHeader("Content-Type", "application/json")
        request.setResponseCode(200)
        return output_lines

    @app.route('/stop', methods=['POST'])
    def stop(self, request):
        """
        Kill current execution
        """
        self.current_process.kill()

        request.setResponseCode(200)
        return None


if __name__ == '__main__':
    store = ItemStore()
    store.app.run('0.0.0.0', 15508)

Ну, проблема в том, что, если мне нужно остановить текущее выполнение, запрос «stop» не будет присутствовать, пока запрос «run» не завершится, поэтому он имеетнет смысла работать таким образом.Я читал несколько страниц о решении async / await, но не могу заставить его работать !.Я думаю, что наиболее выдающееся решение находится на этой веб-странице https://crossbario.com/blog/Going-Asynchronous-from-Flask-to-Twisted-Klein/, однако «запуск» все еще является синхронным процессом.Я только что опубликовал свой основной и оригинальный код, чтобы не путать с изменениями веб-страницы.

С уважением

1 Ответ

0 голосов
/ 27 января 2019

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

Вы должны написать код приложения, чтобы он был не блокирующим, а не блокирующим.

Переключите код из модуля подпроцесса Поддержка процесса Twisted .

Использование возможности Кляйна по возврату отложенного вместо результата (если вы хотите инкрементные результаты во время выполнения процесса, такжепосмотрите на интерфейс запроса - в частности, метод write - чтобы вы могли записать эти результаты до того, как отложенное сработало с окончательным результатом).

ПослеОтсрочка имеет смысл для вас, тогда вы можете подумать о синтаксическом сахаре, который доступен в форме async / await. До тех пор, пока вы не поймете, что делают Deferreds, async / await будет просто черной магией, которая будет работать в ваших программах только случайно.

...