首页 > 解决方案 > 将 flask.request 传递给另一个线程

问题描述

我对是否可以将 Flask 的request对象发送到另一个线程进行处理感到有点困惑。我正在尝试使用在 Elasticsearch 中存储与请求相关的数据after_request。为了尽快处理请求,我试图将处理卸载到单独的线程:

from datetime import datetime
import socket
from threading import Thread

from elasticsearch import Elasticsearch
from flask import current_app, request

def after_request(response):
    Thread(
        target=_process_data, args=(
            current_app._get_current_object(),
            request._get_current_object()
        )
    ).start()

    return response

def _process_data(app, request):
    data = {
        'timestamp': datetime.utcnow(),
        'scheme': request.environ.get('REQUEST_SCHEME'),
        'protocol': request.environ.get('SERVER_PROTOCOL'),
        'method': request.environ.get('REQUEST_METHOD'),
        'uri': request.environ.get('REQUEST_URI'),
        'remote_addr': request.environ.get('REMOTE_ADDR'),
        'remote_port': int(request.environ.get('REMOTE_PORT')),
        'server_name': request.environ.get('SERVER_NAME'),
        'server_port': int(request.environ.get('SERVER_PORT')),
        'app_server': socket.gethostname(),
        'request_headers': dict(request.headers)
    }

    elastic = Elasticsearch('localhost:9200')
    elastic.index(index=app.config['TRACKING_ES_INDEX'], doc_type='_doc', body=data)

但是,我开始在 Elasticsearch 中看到的是带有空request_headers字段 ( {}) 的文档,尤其是在对应用程序进行负载测试时。当我尝试将data字典填充到after_request并传递data到时_process_data,一切都按预期工作。

文档指出:

上下文对于每个线程(或其他工作类型)都是唯一的。请求不能传递给另一个线程,另一个线程将有不同的上下文堆栈,并且不会知道父线程指向的请求。

但是,在几段之后,它指出:

在某些情况下需要对代理对象的引用,例如发送信号或将数据传递给后台线程。

所以我假设使用request._get_current_object()来获取实际对象并将其传递给分离的线程会起作用。但显然,我错过了一些东西......

标签: pythonflaskthread-safety

解决方案


推荐阅读