Ejemplo n.º 1
0
    def del_pid(self):
        """
        Delete PID callback function. This function will be called on sys.exit to delete pid file.

        :return: None
        """
        logger.info("Deleting pid file...")
        if os.path.exists(self.pid_file):
            os.remove(self.pid_file)
        self.daemon_alive = False
Ejemplo n.º 2
0
    def signal_handler(self):
        """
        Register callback function on receiving interrupt signal during prepare daemon environment.
        Note: it will only take effects in this function.

        :return: None
        """
        logger.info("Received interrupt signal, processing exit callback...")
        self.daemon_alive = False
        sys.exit(0)
Ejemplo n.º 3
0
    def restart(self, *args, **kwargs):
        """
        Restart a daemon progress

        :param args: Tuple args input, type: tuple
        :param kwargs: Dict args input, type: dict
        :return: None
        """
        logger.info("Restarting daemon...")
        self.stop()
        self.start(*args, **kwargs)
Ejemplo n.º 4
0
    def switch_verbose(self):
        """
        Switch debug mode to control print log on screen or just in log file.

        :return: None
        """
        # Verbose mode ON is print log on screen, since we use logger so its ON/OFF is not useful
        if self.verbose:
            logger.info("Verbose switch ON")
            self.stdin = sys.stdin
            self.stdout = sys.stdout
            self.stderr = sys.stderr
        # Verbose mode OFF
        else:
            logger.info("Verbose switch OFF")
            self.stdin = os.devnull
            self.stdout = os.devnull
            self.stderr = os.devnull
Ejemplo n.º 5
0
    def run(self, *args, **kwargs):
        """
        Run exact process you want as daemon service. You should put your process in this function.
        Usage: You can use this by bellow suggestions:
        1. Your process should running independently, then put your running command here to call it.
        2. Your can copy the whole daemon code into your project then integrate with your project.
        3. Suggest call your process with sync/block ways, it will make sure your process will not running concurrently
           only except the situation you want it to. You can use: os.system(command), subprocess.call(command).etc.

        :param args: Tuple args input, type: tuple
        :param kwargs: Dict args input, type: dict
        :return: None
        """
        logger.info("Daemon process start running...")
        while True:
            os.system(self.process)
            logger.warning("Process will rerun after %s seconds." %
                           self.interval)
            time.sleep(self.interval)
Ejemplo n.º 6
0
    def start(self, *args, **kwargs):
        """
        Start a daemon progress

        :param args: Tuple args input, type: tuple
        :param kwargs: Dict args input, type: dict
        :return: None
        """
        logger.info("Starting daemon process...")
        # checking pid file to see if the daemon already running
        pid = self.get_pid()
        if pid:
            msg = 'pid file %s already exists, is daemon process already running?\n'
            logger.info(msg % self.pid_file)
            sys.stderr.write(msg % self.pid_file)
            sys.exit(1)
        # Prepare daemon context
        self.daemonize()
        # Start daemon process
        self.run(*args, **kwargs)
Ejemplo n.º 7
0
    def redirect_std_info(self):
        """
        Redirect STD I/O object

        :return: None
        """
        logger.info("Redirecting std info and file description objects...")
        logger.warning(
            "After redirect all log will not show in console, you may need check daemon status by command "
            "or in log file!")
        sys.stdout.flush()
        sys.stderr.flush()

        with open(self.stdin, 'r') as s_in:
            os.dup2(s_in.fileno(), sys.stdin.fileno())
        with open(self.stdout, 'a+') as s_out:
            os.dup2(s_out.fileno(), sys.stdout.fileno())
        if self.stderr:
            with open(self.stderr, 'a+') as s_err:
                os.dup2(s_err.fileno(), sys.stderr.fileno())
Ejemplo n.º 8
0
def show_title_info(action, process, interval):
    """
    Show title brief info

    :param action: User actions, type: str
    :param process: User process, type: str
    :param interval: User interval time, type: int
    :return: None
    """
    logger.info(
        "=========================================== Daemon Begin ============================================"
    )
    logger.info("Daemon Action: %s, Process: '%s', Interval: %ss" %
                (action, process, interval))
    logger.info(
        "====================================================================================================="
    )
Ejemplo n.º 9
0
    def status(self):
        """
        Check current daemon service status

        :return: None
        """
        logger.info("Checking daemon status...")
        try:
            pid = self.get_pid()
        except IOError:
            pid = None

        if not pid:
            message = "No such process running.\n"
            logger.info(message)
            sys.stderr.write(message)
        else:
            message = "The process is running, PID is %s .\n"
            logger.info(message % str(pid))
            sys.stderr.write(message % str(pid))
Ejemplo n.º 10
0
    def stop(self):
        """
        Terminate a daemon progress

        :return: None
        """
        logger.info("Stopping daemon process...")
        # Get pid
        try:
            pid = self.get_pid()
        except IOError:
            pid = None

        # If process not run return
        if not pid:
            msg = 'pid file [%s] not exists, daemon process NOT running!\n'
            logger.info(msg % self.pid_file)
            sys.stderr.write(msg % self.pid_file)
            if os.path.exists(self.pid_file):
                os.remove(self.pid_file)
            return

        # Try to kill daemon process
        try:
            i = 0
            while True:
                os.kill(pid, signal.SIGTERM)
                time.sleep(0.1)
                i = i + 1
                if i % 10 == 0:
                    os.kill(pid, signal.SIGHUP)
        except OSError as err:
            err = str(err)
            if err.find('No such process') > 0:
                if os.path.exists(self.pid_file):
                    os.remove(self.pid_file)
            else:
                logger.error("Catch error info: %s while stopping!" % str(err))
                sys.exit(1)
        logger.info("Daemon process stopped successfully!")
Ejemplo n.º 11
0
def show_end_info():
    """ Show end info """
    logger.info(
        "============================================= Daemon End ============================================"
    )
Ejemplo n.º 12
0
    def daemonize(self):
        """
        The main function to prepare a daemon environment.
        It has 6 steps:
        1. Fork main process and make sure sub process running as PGID leader
        2. Create new session SID in sub progress
        3. Switch working directory to new default and reset file access umask privilege
        4. Second fork sub process to a new grand sub progress and handover it to system init progress pid(1)
        5. Close all not used file description objects which in sub progress and redirect them
        6. Register exit call back function to process tasks after receiving exit signal.

        :return: None
        """
        # Step 1: Create sub process by using fork
        logger.info("Step 1: Create sub process...")
        self.fork_sub_process()

        # Step 2: Create new session in sub process by using setsid
        logger.info("Step 2: Create new session id...")
        os.setsid(
        )  # After setsid, sub-process pid will > 0 and will be host of pgid

        # Step 3: Switch current working directory and reset file umask privilege
        logger.info(
            "Step 3: Switch current working directory and reset file umask privilege..."
        )
        os.chdir(self.path)
        os.umask(self.umask)

        # Step 4: Second fork grand sub-process
        logger.info("Step 4: Second forking sub-process...")
        self.fork_sub_process()

        # Step 5: Close not used file description objects
        logger.info("Step 5: Closing not used file description objects...")
        self.redirect_std_info()

        # Step 6: Register exit callback and listening signal interruption
        logger.info(
            "Step 6: Registering exit callback and listening signal interruption..."
        )
        # Register exit callback function
        atexit.register(self.del_pid)
        pid = str(os.getpid())
        with open(self.pid_file, 'w+') as fw:
            fw.write('%s\n' % pid)

        # Watching signal interrupt. Add signal callback here to better process system exit behavior.
        signal.signal(signal.SIGTERM, self.signal_handler)
        signal.signal(signal.SIGINT, self.signal_handler)
        signal.signal(signal.SIGHUP, self.signal_handler)