sql >> Databasteknik >  >> RDS >> PostgreSQL

Django ORM läcker anslutningar när du använder ThreadPoolExecutor

Min gissning är att ThreadPoolExecutor är inte det som skapar DB-anslutningen, utan de gängade jobben är de som håller anslutningen. Jag har redan fått ta itu med det här.

Det slutade med att jag byggde detta omslag för att säkerställa att trådar stängs manuellt när jobb görs i en ThreadPoolExecutor. Detta bör vara användbart för att säkerställa att anslutningar inte läcker, än så länge har jag inte sett något läckage när jag använder den här koden.

from functools import wraps
from concurrent.futures import ThreadPoolExecutor
from django.db import connection

class DjangoConnectionThreadPoolExecutor(ThreadPoolExecutor):
    """
    When a function is passed into the ThreadPoolExecutor via either submit() or map(), 
    this will wrap the function, and make sure that close_django_db_connection() is called 
    inside the thread when it's finished so Django doesn't leak DB connections.

    Since map() calls submit(), only submit() needs to be overwritten.
    """
    def close_django_db_connection(self):
        connection.close()

    def generate_thread_closing_wrapper(self, fn):
        @wraps(fn)
        def new_func(*args, **kwargs):
            try:
                return fn(*args, **kwargs)
            finally:
                self.close_django_db_connection()
        return new_func

    def submit(*args, **kwargs):
        """
        I took the args filtering/unpacking logic from 
   
        https://github.com/python/cpython/blob/3.7/Lib/concurrent/futures/thread.py 
        
        so I can properly get the function object the same way it was done there.
        """
        if len(args) >= 2:
            self, fn, *args = args
            fn = self.generate_thread_closing_wrapper(fn=fn)
        elif not args:
            raise TypeError("descriptor 'submit' of 'ThreadPoolExecutor' object "
                        "needs an argument")
        elif 'fn' in kwargs:
            fn = self.generate_thread_closing_wrapper(fn=kwargs.pop('fn'))
            self, *args = args
    
        return super(self.__class__, self).submit(fn, *args, **kwargs)

Då kan du bara använda detta:

    with DjangoConnectionThreadPoolExecutor(max_workers=15) as executor:
        results = list(executor.map(func, args_list))

...och var säker på att anslutningarna kommer att stängas.




  1. Hur ändrar man dubbletter av rader till unika värden i mysql?

  2. PDO Ansluta med ett krypterat lösenord?

  3. Skicka parametrar från en batchfil till sqlplus-skript

  4. Var man lagrar uppladdade filer (ljud, bilder och video)