Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What is going on with this article?
@t-kigi

Django内部でThreadを使う場合に意図せぬコネクションリークが発生

More than 1 year has passed since last update.

はじめに

Djangoの内部で時間のかかるリクエストを処理したり、バッチ処理拡張モジュールを自作する場合などに並列処理実装として自分でスレッドを作成し、利用することがある。
今回このケースで長期運用していると Too many connections が発生したので、その調査結果をメモ。

原因

  • DjangoのDBコネクションは スレッドごと に作成される
    • DBアクセスが発生する場合のみ。 モデルへのアクセスがない別スレッドはそもそもDBコネクションを生成しないので問題ない
    • コネクションを利用する際、スレッドローカル相当の機能内にコネクションが保持されており、ここに無い場合は初回アクセス時にコネクションを生成する
    • https://github.com/django/django/blob/master/django/db/utils.py#L136 の ConnectionHandlerが実体で self._connections 内にコネクションを格納
  • 自分で作った別スレッドの中でDjangoのモデルを使う場合にはDBコネクション管理を意識する必要がある
  • スレッドローカル実装の定期解放処理時に解放される場合もあるが、実装が入り組んでいる場合解放されないこともあるし、待っている間にも上限は近づいてくる

対処

I/Oコストはかかるものの、スレッド終了時にコネクションを close_all で明示的に閉じることでコネクションリークは防ぐことができる。
とはいえ、そもそも何らかの理由(おそらく処理時間の問題)があって別スレッドを立てているはずなので、コネクションの作成・解放はそこまで大きな問題にはならないはず。

from django.db import connections

def target():
    ''' 別スレッドで実行される関数 '''
    try:
        # 処理
    finally:
        connections.close_all()

ちなみに、close_all は "同一スレッド内の全てのDBを閉じる" 関数である(Djangoは設定に DATABASES として複数のDBを設定することが可能)。 別スレッドのDBを閉じたりはしない。

1
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
t-kigi
仕事上で引っかかった技術的事項のメモ帳として使います。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
1
Help us understand the problem. What is going on with this article?