Django multiprocessing and database connections

前端 未结 9 820
挽巷
挽巷 2020-11-28 03:16

Background:

I\'m working a project which uses Django with a Postgres database. We\'re also using mod_wsgi in case that matters, since some of my web searches have m

相关标签:
9条回答
  • 2020-11-28 04:03

    I had "closed connection" issues when running Django test cases sequentially. In addition to the tests, there is also another process intentionally modifying the database during test execution. This process is started in each test case setUp().

    A simple fix was to inherit my test classes from TransactionTestCase instead of TestCase. This makes sure that the database was actually written, and the other process has an up-to-date view on the data.

    0 讨论(0)
  • 2020-11-28 04:06

    For Python 3 and Django 1.9 this is what worked for me:

    import multiprocessing
    import django
    django.setup() # Must call setup
    
    def db_worker():
        for name, info in django.db.connections.databases.items(): # Close the DB connections
            django.db.connection.close()
        # Execute parallel code here
    
    if __name__ == '__main__':
        multiprocessing.Process(target=db_worker)
    

    Note that without the django.setup() I could not get this to work. I am guessing something needs to be initialized again for multiprocessing.

    0 讨论(0)
  • 2020-11-28 04:09

    Hey I ran into this issue and was able to resolve it by performing the following (we are implementing a limited task system)

    task.py

    from django.db import connection
    
    def as_task(fn):
        """  this is a decorator that handles task duties, like setting up loggers, reporting on status...etc """ 
        connection.close()  #  this is where i kill the database connection VERY IMPORTANT
        # This will force django to open a new unique connection, since on linux at least
        # Connections do not fare well when forked 
        #...etc
    

    ScheduledJob.py

    from django.db import connection
    
    def run_task(request, job_id):
        """ Just a simple view that when hit with a specific job id kicks of said job """ 
        # your logic goes here
        # ...
        processor = multiprocessing.Queue()
        multiprocessing.Process(
            target=call_command,  # all of our tasks are setup as management commands in django
            args=[
                job_info.management_command,
            ],
            kwargs= {
                'web_processor': processor,
            }.items() + vars(options).items()).start()
    
    result = processor.get(timeout=10)  # wait to get a response on a successful init
    # Result is a tuple of [TRUE|FALSE,<ErrorMessage>]
    if not result[0]:
        raise Exception(result[1])
    else:
       # THE VERY VERY IMPORTANT PART HERE, notice that up to this point we haven't touched the db again, but now we absolutely have to call connection.close()
       connection.close()
       # we do some database accessing here to get the most recently updated job id in the database
    

    Honestly, to prevent race conditions (with multiple simultaneous users) it would be best to call database.close() as quickly as possible after you fork the process. There may still be a chance that another user somewhere down the line totally makes a request to the db before you have a chance to flush the database though.

    In all honesty it would likely be safer and smarter to have your fork not call the command directly, but instead call a script on the operating system so that the spawned task runs in its own django shell!

    0 讨论(0)
提交回复
热议问题