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?