deamon
This commit is contained in:
parent
decca46a14
commit
c16560cf99
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1,5 @@
|
|||||||
packages
|
packages
|
||||||
venv
|
venv
|
||||||
.idea
|
.idea
|
||||||
__pycache__
|
__pycache__
|
||||||
|
errlog.txt
|
207
daemon/SimpleDaemon.py
Normal file
207
daemon/SimpleDaemon.py
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
"""Generic linux daemon base class for python 3.x."""
|
||||||
|
|
||||||
|
import sys, os, time, atexit, signal, logging
|
||||||
|
|
||||||
|
|
||||||
|
class Daemon:
|
||||||
|
"""A generic daemon class.
|
||||||
|
|
||||||
|
Usage: subclass the daemon class and override the run() method."""
|
||||||
|
|
||||||
|
def __init__(self, pidfile, error_log_file='/dev/null'):
|
||||||
|
self.logging = logging
|
||||||
|
self.logging.basicConfig(filename=error_log_file, filemode='w',
|
||||||
|
format='%(name)s - %(levelname)s - %(message)s\n')
|
||||||
|
self.logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))
|
||||||
|
self.error_log_file = error_log_file
|
||||||
|
self.pidfile = pidfile
|
||||||
|
self.commands = {}
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.base_commands()
|
||||||
|
self.reg_command()
|
||||||
|
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def daemonize(self):
|
||||||
|
"""Deamonize class. UNIX double fork mechanism."""
|
||||||
|
|
||||||
|
try:
|
||||||
|
pid = os.fork()
|
||||||
|
if pid > 0:
|
||||||
|
# exit first parent
|
||||||
|
sys.exit(0)
|
||||||
|
except OSError as err:
|
||||||
|
sys.stderr.write('fork #1 failed: {0}\n'.format(err))
|
||||||
|
self.logging.error('fork #1 failed: {0}\n'.format(err))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# decouple from parent environment
|
||||||
|
os.chdir('/')
|
||||||
|
os.setsid()
|
||||||
|
os.umask(0)
|
||||||
|
|
||||||
|
# do second fork
|
||||||
|
try:
|
||||||
|
pid = os.fork()
|
||||||
|
if pid > 0:
|
||||||
|
# exit from second parent
|
||||||
|
sys.exit(0)
|
||||||
|
except OSError as err:
|
||||||
|
sys.stderr.write('fork #2 failed: {0}\n'.format(err))
|
||||||
|
self.logging.error('fork #2 failed: {0}\n'.format(err))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# redirect standard file descriptors
|
||||||
|
sys.stdout.flush()
|
||||||
|
sys.stderr.flush()
|
||||||
|
si = open(os.devnull, 'r')
|
||||||
|
so = open(os.devnull, 'a+')
|
||||||
|
se = open(os.devnull, 'a+')
|
||||||
|
|
||||||
|
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||||
|
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||||
|
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||||
|
|
||||||
|
# write pidfile
|
||||||
|
atexit.register(self.delpid)
|
||||||
|
|
||||||
|
pid = str(os.getpid())
|
||||||
|
with open(self.pidfile, 'w+') as f:
|
||||||
|
f.write(pid + '\n')
|
||||||
|
|
||||||
|
def delpid(self):
|
||||||
|
os.remove(self.pidfile)
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""Start the daemon."""
|
||||||
|
self.logging.info("Start")
|
||||||
|
|
||||||
|
# Check for a pidfile to see if the daemon already runs
|
||||||
|
try:
|
||||||
|
with open(self.pidfile, 'r') as pf:
|
||||||
|
|
||||||
|
pid = int(pf.read().strip())
|
||||||
|
except IOError:
|
||||||
|
pid = None
|
||||||
|
|
||||||
|
if pid:
|
||||||
|
message = "pidfile {0} already exist. " + \
|
||||||
|
"{warning}Daemon already running?{end}\n".format(warning=Bcolors.WARNING, end=Bcolors.ENDC)
|
||||||
|
sys.stderr.write(message.format(self.pidfile))
|
||||||
|
self.logging.error(message.format(self.pidfile))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Start the daemon
|
||||||
|
print("{green}The process {name} has been successfully launched{end}".format(name=self.pidfile, green=Bcolors.OKGREEN, end=Bcolors.ENDC))
|
||||||
|
self.daemonize()
|
||||||
|
self.run()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""Stop the daemon."""
|
||||||
|
self.logging.info("Stop")
|
||||||
|
|
||||||
|
# Get the pid from the pidfile
|
||||||
|
try:
|
||||||
|
with open(self.pidfile, 'r') as pf:
|
||||||
|
pid = int(pf.read().strip())
|
||||||
|
except IOError:
|
||||||
|
pid = None
|
||||||
|
|
||||||
|
if not pid:
|
||||||
|
message = "pidfile {0} does not exist. " + \
|
||||||
|
"Daemon not running?\n"
|
||||||
|
sys.stderr.write(message.format(self.pidfile))
|
||||||
|
self.logging.error(message.format(self.pidfile))
|
||||||
|
return # not an error in a restart
|
||||||
|
|
||||||
|
# Try killing the daemon process
|
||||||
|
try:
|
||||||
|
while 1:
|
||||||
|
os.kill(pid, signal.SIGTERM)
|
||||||
|
time.sleep(0.1)
|
||||||
|
except OSError as err:
|
||||||
|
e = str(err.args)
|
||||||
|
if e.find("No such process") > 0:
|
||||||
|
if os.path.exists(self.pidfile):
|
||||||
|
os.remove(self.pidfile)
|
||||||
|
else:
|
||||||
|
print(str(err.args))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def restart(self):
|
||||||
|
"""Restart the daemon."""
|
||||||
|
self.logging.info("Restart")
|
||||||
|
self.stop()
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
def status(self):
|
||||||
|
print("Status")
|
||||||
|
try:
|
||||||
|
with open(self.pidfile, 'r') as pf:
|
||||||
|
|
||||||
|
pid = int(pf.read().strip())
|
||||||
|
except IOError:
|
||||||
|
pid = None
|
||||||
|
|
||||||
|
if pid:
|
||||||
|
print("Process started, name {name} | pid {pid}".format(pid=pid, name=self.pidfile))
|
||||||
|
else:
|
||||||
|
print("Process is not running")
|
||||||
|
|
||||||
|
def console_stdout(self):
|
||||||
|
sys.stdout = sys.__stdout__
|
||||||
|
print(123)
|
||||||
|
|
||||||
|
def process_command(self):
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
command = sys.argv[1]
|
||||||
|
handler = self.get_command_handler(command)
|
||||||
|
if handler:
|
||||||
|
handler()
|
||||||
|
else:
|
||||||
|
print("Unknown command: %s" % command)
|
||||||
|
else:
|
||||||
|
print("usage: %s start|stop|restart|status" % sys.argv[0])
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
def base_commands(self):
|
||||||
|
self.add_command('start', self.start)
|
||||||
|
self.add_command('stop', self.stop)
|
||||||
|
self.add_command('restart', self.restart)
|
||||||
|
self.add_command('status', self.status)
|
||||||
|
self.add_command('console_stdout', self.console_stdout)
|
||||||
|
|
||||||
|
def add_command(self, command, handler):
|
||||||
|
if command not in self.commands:
|
||||||
|
self.commands[command] = handler
|
||||||
|
|
||||||
|
def get_command_handler(self, command):
|
||||||
|
if command in self.commands:
|
||||||
|
return self.commands[command]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def reg_command(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""You should override this method when you subclass Daemon.
|
||||||
|
|
||||||
|
It will be called after the process has been daemonized by
|
||||||
|
start() or restart()."""
|
||||||
|
|
||||||
|
|
||||||
|
class Bcolors:
|
||||||
|
HEADER = '\033[95m'
|
||||||
|
OKBLUE = '\033[94m'
|
||||||
|
OKCYAN = '\033[96m'
|
||||||
|
OKGREEN = '\033[92m'
|
||||||
|
WARNING = '\033[93m'
|
||||||
|
FAIL = '\033[91m'
|
||||||
|
ENDC = '\033[0m'
|
||||||
|
BOLD = '\033[1m'
|
||||||
|
UNDERLINE = '\033[4m'
|
0
daemon/__init__.py
Normal file
0
daemon/__init__.py
Normal file
16
main.py
16
main.py
@ -1,16 +1,16 @@
|
|||||||
# This is a sample Python script.
|
import uvicorn
|
||||||
|
from server import app
|
||||||
# Press Shift+F10 to execute it or replace it with your code.
|
from daemon.SimpleDaemon import Daemon
|
||||||
# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.
|
|
||||||
|
|
||||||
|
|
||||||
def print_hi(name):
|
class CdnServerDaemon(Daemon):
|
||||||
# Use a breakpoint in the code line below to debug your script.
|
def run(self):
|
||||||
print(f'Hi, {name}') # Press Ctrl+F8 to toggle the breakpoint.
|
uvicorn.run("server:app", port=5000, log_level="info")
|
||||||
|
|
||||||
|
|
||||||
# Press the green button in the gutter to run the script.
|
# Press the green button in the gutter to run the script.
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
print_hi('PyCharm')
|
with CdnServerDaemon('/tmp/daemon-cdn-server.pid', error_log_file='errlog.txt') as daemon:
|
||||||
|
daemon.process_command()
|
||||||
|
|
||||||
# See PyCharm help at https://www.jetbrains.com/help/pycharm/
|
# See PyCharm help at https://www.jetbrains.com/help/pycharm/
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from typing import Union, Annotated
|
from typing import Union, Annotated
|
||||||
|
import uvicorn
|
||||||
|
|
||||||
from fastapi import FastAPI, File, UploadFile, Form, Response, status
|
from fastapi import FastAPI, File, UploadFile, Form, Response, status
|
||||||
|
|
||||||
@ -47,4 +48,8 @@ async def create_upload_file(file: UploadFile | None, package: Annotated[str, Fo
|
|||||||
finally:
|
finally:
|
||||||
file.file.close()
|
file.file.close()
|
||||||
|
|
||||||
return {"message": f"Successfully uploaded {file.filename}"}
|
return {"message": f"Successfully uploaded {file.filename}"}
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
uvicorn.run("server:app", port=5000, log_level="info")
|
Loading…
Reference in New Issue
Block a user