How to properly delete lockfile in a python abstract class?

262 views Asked by At

I have a python3 cron script that consists of a MyCron class and a MyIMAP class.

The MyCron class is an abstract class that makes sure only one instance of the script runs. It creates and destroys a lock file and throws a SingleInstanceExeption when cron tries to run the script when it's already running.

The MyIMAP class inherits the MyCron class as its base class. It checks email and returns unread emails. If anything goes wrong, I want my script to neatly close the connection and destroy the lockfile.

In both classes I am overriding __del__ method. In MyCron because I need to remove the lock, and in MyIMAP to close the connection.

I am experiencing weird results (objects no longer existing) when __del__ is invoked. Here's a sample of the code:

class MyCron(object):
    def __init__(self, jobname=os.path.basename(sys.argv[0]).split('.')[0]):
        self.logger = logging.getLogger(__name__)
        self.initialized = False
        lockfilename  = "mycron"
        lockfilename += "-%s.lock" % jobname if jobname else ".lock"
        self.lockfile = os.path.normpath(tempfile.gettempdir() + '/' + lockfilename)
        self.logger.debug("MyCron lockfile: " + self.lockfile)
        self.fp = open(self.lockfile, 'w')
        self.fp.flush()
        try:
            fcntl.lockf(self.fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
            self.initialized = True
        except IOError:
            self.logger.warning("Another %s MyCron is already running, quitting." % jobname)
            raise SingleInstanceException()
            self.initialized = False

    def __del__(self):
        if not self.initialized:
            return
        try:
            fcntl.lockf(self.fp, fcntl.LOCK_UN)
            # os.close(self.fp)
            if os.path.isfile(self.lockfile):
                os.unlink(self.lockfile)
        except Exception as e:
            if self.logger:
                self.logger.warning(e)
            else:
                print("Unloggable error: %s" % e)
            sys.exit(-1)

class MyIMAP(MyCron):
    def __init__(self, server, username, password, port=993, timeout=60):
        super(MyIMAP, self).__init__()
        self.server     = server
        self.username   = username
        self.password   = password
        self.port       = port
        self.connection = None
        if self.initialized:
            socket.setdefaulttimeout(timeout)
            self.connect()
            self.login()

    def __del__(self):
        super(MyIMAP, self).__del__()
        if self.initialized and self.connection:
            self.connection.logout()
            self.logger.info("Close connection to %s:%d" % (self.server, self.port))

    ...

I understand this is related to the unpredictable nature of the __del__ method, and I should probably be implementing this a different way. What's the best practice here for python 3?

0

There are 0 answers