Почему Flask-SocketIO (с Gevent) приостанавливается при выполнении запроса к БД? - PullRequest
0 голосов
/ 20 марта 2019

Я работаю в веб-приложении для своей компании.Недавно я столкнулся с «базовой» проблемой создания сценариев SQL в базе данных (OracleDB).

Я использую веб-сервер Flask-SocketIO с async-mode = 'gevent', и, очевидно, когда вывыполнить cx_Oracle.connection.cursor.execute (), блокирует все мое приложение, пока не вернется ответ (веб-сервер перестает получать запросы других пользователей).

Я ищу ответ на вопрос, и я понял, чтоcx_Oracle не работает параллельно с другими клиентами и запросами.

Пример проблемы:

from gevent import monkey; monkey.patch_all()
from flask_socketio import SocketIO
from flask import Flask
import cx_Oracle

app = Flask(__name__, template_folder='templates')

app.secret_key = 'testing'
app.config['DEBUG'] = False

socketio = SocketIO(app, async_mode='gevent')

@app.route('/')
def index():
    sql_query = 'select * from blabla'
    connection = cx_Oracle.connect(user, password, host, threaded=True)
    cursor = connection.cursor()
    cursor.execute(sql_query)
    transacoes = cursor.fetchall()

socketio.run(app, host='localhost', port=5005)

Когда я делаю более 1 запроса на http://localhost/,, мое приложение не 't ответить на запросы 2+, пока не выполнится первая.

Я пытался реализовать gevent.ThreadPool, чтобы выполнить более 1 запроса параллельно, но я столкнулся с проблемой:

Примеркод с gevent.ThreadPool:

from gevent import monkey; monkey.patch_all()
from gevent.threadpool import ThreadPool
from flask_socketio import SocketIO
from flask import Flask
import cx_Oracle

app = Flask(__name__, template_folder='templates')

app.secret_key = 'testing'
app.config['DEBUG'] = False

socketio = SocketIO(app, async_mode='gevent')

def receive_data(user, password, host, sql_query):
    connection = cx_Oracle.connect(user, password, host, threaded=True)
    cursor = connection.cursor()
    cursor.execute(sql_query)
    response = cursor.fecthall()
    cursor.close()
    connection.close()
    return response

@app.route('/')
def index():
    sql_query = 'select * from blabla'

    pool = ThreadPool(1) # I tried with more than 100
    async_result = pool.apply_async(receive_data,
                                    args=(user, password, host, sql_query))
    transacoes = async_result.get()


socketio.run(app, host='localhost', port=5005)

Я получаю сообщение об ошибке при выполнении нескольких запросов в receive_data ():

RuntimeError: Работа вне контекста приложения.

Обычно это означает, что вы пытались использовать функциональность, необходимую для взаимодействия с текущим объектом приложения.Чтобы решить эту проблему, настройте контекст приложения с помощью app.app_context ().См. Документацию для получения дополнительной информации.

И:

'LoopExit: эта операция блокирует навсегда

Ответы [ 2 ]

0 голосов
/ 12 июля 2019

Я нашел другое решение для этой проблемы.

Когда модуль не поддерживает monkey_path, eventlet предлагает вам использовать eventlet.tpool http://eventlet.net/doc/threading.html.

Пример:

from eventlet import tpool
cur = tpool.execute(cx_Oracle.connect, connection_string, *args, **kwargs)

Это решает основную проблему, и теперь я могу использовать socketio с async_mode = eventlet.

0 голосов
/ 21 марта 2019

Чтобы решить эту проблему, я изменяю async_mode='gevent' на async_mode='threading' и удаляю monkey_patch().

Я не знаю, как это повлияет на мое приложение, но вся система работает нормально.

...