Search code examples
pythonservicecelerysftpgunicorn

Is there a way in Django to execute some python code only once when gunicorn / celery services are getting restarted?


My Django Application contains celery based tasks, which download certain files from a SFTP server every time it executes. Till now i create an SFTP connection every time a job starts and close the connection at the end of job. But some how it is cause file descriptor error in code (too many SFTP connection opened). I am thinking of making SFTP connection via a singleton class so that only one SFTP connection gets established and that to only at the time when i start the gunicorn/celery services.

Is there a way i can execute the python code to create an SFTP connection only once when the application comes up or gets restarted? and its closed the services are stopped?


Solution

  • Singleton class

    class Singleton:
        def __init__(self, klass):
            self.klass = klass
            self.instance = None
    
        def __call__(self, *args, **kwds):
            if self.instance is None:
                self.instance = self.klass(*args, **kwds)
            return self.instance
    
    @Singleton
    class SFTP_SINGLETON(object):
    
        def __init__(self, hostname=None, username=None, password=None, port=22, default_path=None):
    
            self._hostname = hostname
            self._username = username
            self._Password = password
    
            self._sftp = None
            self._port = port
            self._default_path = default_path
            self._sftp_live = False
            self._transport = self._start_transport()
    
        def _start_transport(self):
            try:
                self._transport = paramiko.Transport((self._hostname, self._port))
                self._transport.connect(username=self._username, password=self._Password)
                logger.info(" connected to {} : {}".format(self._hostname, self._port))
                return self._transport
            except (AttributeError, socket.gaierror) as e:
                # couldn't connect
                logger.info(" exception in establish_connection : %s ", e)
                raise ConnectionException(self._hostname, self._port)
    
        def connect(self):
            """Establish the SFTP connection."""
            if not self._sftp_live:
                self._sftp = paramiko.SFTPClient.from_transport(self._transport)
                # if self._default_path is not None:
                #     self._sftp.chdir(self._default_path)
                self._sftp_live = True
    
        def close(self):
            """Closes the connection and cleans up."""
            # Close SFTP Connection.
            if self._sftp_live:
                self._sftp.close()
                self._sftp_live = False
            # Close the SSH Transport.
            if self._transport:
                self._transport.close()
                self._transport = None