Django multiprocessing and database connections

前端 未结 9 864
挽巷
挽巷 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: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,]
    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!

提交回复
热议问题