You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							146 lines
						
					
					
						
							3.9 KiB
						
					
					
				
			
		
		
	
	
							146 lines
						
					
					
						
							3.9 KiB
						
					
					
				import signal
 | 
						|
import threading
 | 
						|
 | 
						|
import daemon
 | 
						|
from daemon import pidfile
 | 
						|
 | 
						|
from .hands import *
 | 
						|
from .hands import __version__
 | 
						|
from .services.base import BaseService
 | 
						|
 | 
						|
 | 
						|
class ServicesUtil(object):
 | 
						|
 | 
						|
    def __init__(self, services, run_daemon=False, force_stop=False, stop_daemon=False):
 | 
						|
        self._services = services
 | 
						|
        self.run_daemon = run_daemon
 | 
						|
        self.force_stop = force_stop
 | 
						|
        self.stop_daemon = stop_daemon
 | 
						|
        self.EXIT_EVENT = threading.Event()
 | 
						|
        self.check_interval = 30
 | 
						|
        self.files_preserve_map = {}
 | 
						|
 | 
						|
    def restart(self):
 | 
						|
        self.stop()
 | 
						|
        time.sleep(5)
 | 
						|
        self.start_and_watch()
 | 
						|
 | 
						|
    def start_and_watch(self):
 | 
						|
        logging.info(time.ctime())
 | 
						|
        logging.info(f'FlyApps version {__version__}, more see https://flyapps.cn')
 | 
						|
        self.start()
 | 
						|
        if self.run_daemon:
 | 
						|
            self.show_status()
 | 
						|
            with self.daemon_context:
 | 
						|
                self.watch()
 | 
						|
        else:
 | 
						|
            self.watch()
 | 
						|
 | 
						|
    def start(self):
 | 
						|
        if 'uwsgi' in [service.name for service in self._services]:
 | 
						|
            prepare()
 | 
						|
            clean_cache()
 | 
						|
 | 
						|
        for service in self._services:
 | 
						|
            service: BaseService
 | 
						|
            service.start()
 | 
						|
            self.files_preserve_map[service.name] = service.log_file
 | 
						|
            time.sleep(1)
 | 
						|
 | 
						|
    def stop(self):
 | 
						|
        for service in self._services:
 | 
						|
            service: BaseService
 | 
						|
            service.stop(force=self.force_stop)
 | 
						|
 | 
						|
        if self.stop_daemon:
 | 
						|
            self._stop_daemon()
 | 
						|
 | 
						|
    # -- watch --
 | 
						|
    def watch(self):
 | 
						|
        while not self.EXIT_EVENT.is_set():
 | 
						|
            try:
 | 
						|
                _exit = self._watch()
 | 
						|
                if _exit:
 | 
						|
                    break
 | 
						|
                time.sleep(self.check_interval)
 | 
						|
            except KeyboardInterrupt:
 | 
						|
                print('Start stop services')
 | 
						|
                break
 | 
						|
        self.clean_up()
 | 
						|
 | 
						|
    def _watch(self):
 | 
						|
        for service in self._services:
 | 
						|
            service: BaseService
 | 
						|
            service.watch()
 | 
						|
            if service.EXIT_EVENT.is_set():
 | 
						|
                self.EXIT_EVENT.set()
 | 
						|
                return True
 | 
						|
        return False
 | 
						|
 | 
						|
    # -- end watch --
 | 
						|
 | 
						|
    def clean_up(self):
 | 
						|
        if not self.EXIT_EVENT.is_set():
 | 
						|
            self.EXIT_EVENT.set()
 | 
						|
 | 
						|
        self.stop()
 | 
						|
 | 
						|
    def show_status(self):
 | 
						|
        for service in self._services:
 | 
						|
            service: BaseService
 | 
						|
            service.show_status()
 | 
						|
 | 
						|
    # -- daemon --
 | 
						|
    def _stop_daemon(self):
 | 
						|
        if self.daemon_pid and self.daemon_is_running:
 | 
						|
            os.kill(self.daemon_pid, 15)
 | 
						|
        self.remove_daemon_pid()
 | 
						|
 | 
						|
    def remove_daemon_pid(self):
 | 
						|
        if os.path.isfile(self.daemon_pid_filepath):
 | 
						|
            os.unlink(self.daemon_pid_filepath)
 | 
						|
 | 
						|
    @property
 | 
						|
    def daemon_pid(self):
 | 
						|
        if not os.path.isfile(self.daemon_pid_filepath):
 | 
						|
            return 0
 | 
						|
        with open(self.daemon_pid_filepath) as f:
 | 
						|
            try:
 | 
						|
                pid = int(f.read().strip())
 | 
						|
            except ValueError:
 | 
						|
                pid = 0
 | 
						|
        return pid
 | 
						|
 | 
						|
    @property
 | 
						|
    def daemon_is_running(self):
 | 
						|
        try:
 | 
						|
            os.kill(self.daemon_pid, 0)
 | 
						|
        except (OSError, ProcessLookupError):
 | 
						|
            return False
 | 
						|
        else:
 | 
						|
            return True
 | 
						|
 | 
						|
    @property
 | 
						|
    def daemon_pid_filepath(self):
 | 
						|
        return os.path.join(TMP_DIR, 'flyapps.pid')
 | 
						|
 | 
						|
    @property
 | 
						|
    def daemon_log_filepath(self):
 | 
						|
        return os.path.join(LOG_DIR, 'flyapps.log')
 | 
						|
 | 
						|
    @property
 | 
						|
    def daemon_context(self):
 | 
						|
        daemon_log_file = open(self.daemon_log_filepath, 'a')
 | 
						|
        context = daemon.DaemonContext(
 | 
						|
            pidfile=pidfile.TimeoutPIDLockFile(self.daemon_pid_filepath),
 | 
						|
            signal_map={
 | 
						|
                signal.SIGTERM: lambda x, y: self.clean_up(),
 | 
						|
                signal.SIGHUP: 'terminate',
 | 
						|
            },
 | 
						|
            stdout=daemon_log_file,
 | 
						|
            stderr=daemon_log_file,
 | 
						|
            files_preserve=list(self.files_preserve_map.values()),
 | 
						|
            detach_process=True,
 | 
						|
        )
 | 
						|
        return context
 | 
						|
    # -- end daemon --
 | 
						|
 |