Python 3 current_についてappがサブスレッドに渡される

2440 ワード

Flaskを勉強していたとき、「Flask Web開発」という本には、スレッドを使った非同期送信メールの例がありました
from . import mail,create_app


def send_async_email(app,msg):
    with app.app_context():
        mail.send(msg)

def send_email(to,subject,template,**kwargs):
    msg = Message(current_app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + subject,
                  sender=current_app.config['FLASKY_MAIL_SENDER'], recipients=[to])
    msg.body = render_template(template + '.txt', **kwargs)
    msg.html = render_template(template + '.txt', **kwargs)
    #with current_app.app_context():
    #    mail.send(msg)
    thr = Thread(target=send_async_email, args=(current_app, msg))
    thr.start()
    return thr


メールを送信すると、エラーが常に発生します.RuntimeError:Working outside of application context.後で資料を探して、current_を渡すことを知っています.appの問題
current_アプリはFlaskでエージェントで、Flaskのソースコードを見ると、外部に包まれていることがわかります.
def _find_app():
    top = _app_ctx_stack.top
    if top is None:
        raise RuntimeError(_app_ctx_err_msg)
    return top.app

...

current_app = LocalProxy(_find_app)

このLocalProxyは展開しませんが、このLocalProxyの役割は、スレッド/コヒーレンスに基づいて現在のコヒーレンス/スレッドに対応するオブジェクトを返すことです.つまり、スレッドAがLocalProxyにAスレッドBを詰め込み、LocalProxyにBを詰め込むことです.どこにいても、スレッドAは永遠にAを取り、スレッドBは永遠にBを取ります.
これはFlaskでrequest、current_をコードで直接使用できることです.appのような変数の下位原因.だから、ここに新しいスレッドが開いているので、実際のオブジェクトを伝えないと、スレッドの中でcurrent_を使用します.appはflaskコンテキストがないため、オブジェクトを取得できません.
リアルオブジェクトを取得するFlaskには、次の方法があります.get_current_object()公式ドキュメントは、次のように解釈されます.
Return the current object. This is useful if you want the real object behind the proxy at a time for performance reasons or because you want to pass the object into a different context.
send_の変更Email関数のコードは次のとおりです.
def send_email(to,subject,template,**kwargs):
    msg = Message(current_app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + subject,
                  sender=current_app.config['FLASKY_MAIL_SENDER'], recipients=[to])
    msg.body = render_template(template + '.txt', **kwargs)
    msg.html = render_template(template + '.txt', **kwargs)
    #with current_app.app_context():
    #    mail.send(msg)
    #current_app          ,                      
    #   _get_current_object             
    app = current_app._get_current_object()
    thr = Thread(target=send_async_email, args=(app, msg))
    thr.start()
    return thr

これで非同期でメールを送信できました