Search code examples
djangopython-3.xpython-decorators

How do I make a decorator for Django management command processing locking?


I have a Django project that has many custom management commands that get executed from crontab. I need to implement locking in these commands to prevent cron from starting multiple instances of the command executions. So I am going through each of my custom management commands and changing:

    def handle(self, *args, **options):
        ...

to:

from lockmgr.lockmgr import LockMgr, Locked

...

    def run_handle(self, *args, **options):
        ''' I renamed handle() to run_handle(). '''
        ...


    def handle(self, *args, **options):

        command = sys.argv[1]
        try:
            with LockMgr(f'{command}_lock') as l:
                self.run_handle(*args, **options)

        except Locked as e:
            errmsg = f'{command} failed to lock. Reason: {e}.'
            self.stdout.write(errmsg)
            self.logger.error(errmsg)

Then I started thinking that I should probably use a "decorator" here, but I am not quite sure how to do that. Any help would be great.

Thanks.


Solution

  • Ah figured it out. I need to create a python file ...

    myproject/decorators/lock_cron_job.py

    from lockmgr.lockmgr import LockMgr, Locked
    import logging
    import sys
    
    
    def lock_cron_job():
        """Decorator that uses LockMgr."""
        def decorator(handle_func):
            def wrapped(*args, **kwargs):
                command = sys.argv[1]
                log = logging.getLogger(command)
                try:
                    with LockMgr(f'{command}_lock'):
                        handle_func(*args, **kwargs)
                except Locked as e:
                    errmsg = f'{command} failed to lock. Reason: {e}'
                    log.error(errmsg)
            return wrapped
        return decorator
    

    and then in my custom management commands I would do this:

    from myproject.decorators.lock_cron_job import lock_cron_job
    
    ...
    
    
        @lock_cron_job()
        def handle(self, *args, **options):
            ...