mirror of
https://github.com/ae-utbm/sith.git
synced 2025-03-10 07:17:11 +00:00
Add a pid file to avoid running honcho multiple times
This commit is contained in:
parent
aa66fc61ab
commit
e542fe11b9
@ -13,6 +13,8 @@
|
|||||||
# OR WITHIN THE LOCAL FILE "LICENSE"
|
# OR WITHIN THE LOCAL FILE "LICENSE"
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
import atexit
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -22,13 +24,14 @@ from sith.composer import start_composer, stop_composer
|
|||||||
from sith.settings import PROCFILE_RUNSERVER
|
from sith.settings import PROCFILE_RUNSERVER
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
logging.basicConfig(encoding="utf-8", level=logging.INFO)
|
||||||
|
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sith.settings")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sith.settings")
|
||||||
|
|
||||||
from django.core.management import execute_from_command_line
|
from django.core.management import execute_from_command_line
|
||||||
|
|
||||||
if os.environ.get(DJANGO_AUTORELOAD_ENV) is None and PROCFILE_RUNSERVER is not None:
|
if os.environ.get(DJANGO_AUTORELOAD_ENV) is None and PROCFILE_RUNSERVER is not None:
|
||||||
start_composer(PROCFILE_RUNSERVER)
|
start_composer(PROCFILE_RUNSERVER)
|
||||||
|
_ = atexit.register(stop_composer)
|
||||||
|
|
||||||
execute_from_command_line(sys.argv)
|
execute_from_command_line(sys.argv)
|
||||||
|
|
||||||
stop_composer()
|
|
||||||
|
@ -1,26 +1,68 @@
|
|||||||
import os
|
import logging
|
||||||
import signal
|
import signal
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import psutil
|
import psutil
|
||||||
|
|
||||||
COMPOSER_PID = "COMPOSER_PID"
|
from sith import settings
|
||||||
|
|
||||||
|
|
||||||
|
def get_pid() -> int | None:
|
||||||
|
"""Read the PID file to get the currently running composer if it exists"""
|
||||||
|
if not settings.COMPOSER_PID_PATH.exists():
|
||||||
|
return None
|
||||||
|
with open(settings.COMPOSER_PID_PATH, "r", encoding="utf8") as f:
|
||||||
|
return int(f.read())
|
||||||
|
|
||||||
|
|
||||||
|
def write_pid(pid: int):
|
||||||
|
"""Write currently running composer pid in PID file"""
|
||||||
|
if not settings.COMPOSER_PID_PATH.exists():
|
||||||
|
settings.COMPOSER_PID_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(settings.COMPOSER_PID_PATH, "w", encoding="utf8") as f:
|
||||||
|
_ = f.write(str(pid))
|
||||||
|
|
||||||
|
|
||||||
|
def delete_pid():
|
||||||
|
"""Delete PID file for cleanup"""
|
||||||
|
settings.COMPOSER_PID_PATH.unlink(missing_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
def is_composer_running() -> bool:
|
||||||
|
"""Check if the process in the PID file is running"""
|
||||||
|
pid = get_pid()
|
||||||
|
if pid is None:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
return psutil.Process(pid).is_running()
|
||||||
|
except psutil.NoSuchProcess:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def start_composer(procfile: str):
|
def start_composer(procfile: str):
|
||||||
"""Starts the composer and stores the PID as an environment variable
|
"""Starts the composer and stores the PID as an environment variable
|
||||||
This allows for running smoothly with the django reloader
|
This allows for running smoothly with the django reloader
|
||||||
"""
|
"""
|
||||||
|
if is_composer_running():
|
||||||
|
logging.info(f"Composer is already running with pid {get_pid()}")
|
||||||
|
logging.info(
|
||||||
|
f"If this is a mistake, please delete {settings.COMPOSER_PID_PATH} and restart the process"
|
||||||
|
)
|
||||||
|
return
|
||||||
process = subprocess.Popen(
|
process = subprocess.Popen(
|
||||||
[sys.executable, "-m", "honcho", "-f", procfile, "start"],
|
[sys.executable, "-m", "honcho", "-f", procfile, "start"],
|
||||||
)
|
)
|
||||||
os.environ[COMPOSER_PID] = str(process.pid)
|
write_pid(process.pid)
|
||||||
|
|
||||||
|
|
||||||
def stop_composer():
|
def stop_composer():
|
||||||
"""Stops the composer if it was started before"""
|
"""Stops the composer if it was started before"""
|
||||||
if (pid := os.environ.get(COMPOSER_PID, None)) is not None:
|
if is_composer_running():
|
||||||
process = psutil.Process(int(pid))
|
process = psutil.Process(get_pid())
|
||||||
|
if process.parent() != psutil.Process():
|
||||||
|
logging.info("Currently running composer is controlled by another process")
|
||||||
|
return
|
||||||
process.send_signal(signal.SIGTERM)
|
process.send_signal(signal.SIGTERM)
|
||||||
process.wait()
|
_ = process.wait()
|
||||||
|
delete_pid()
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import atexit
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from .composer import start_composer, stop_composer
|
from .composer import start_composer, stop_composer
|
||||||
@ -15,7 +17,4 @@ def pytest_load_initial_conftests(early_config, parser, args):
|
|||||||
"""Hook that loads the composer before the pytest-django plugin"""
|
"""Hook that loads the composer before the pytest-django plugin"""
|
||||||
if PROCFILE_PYTEST is not None:
|
if PROCFILE_PYTEST is not None:
|
||||||
start_composer(PROCFILE_PYTEST)
|
start_composer(PROCFILE_PYTEST)
|
||||||
|
_ = atexit.register(stop_composer)
|
||||||
|
|
||||||
def pytest_unconfigure(config):
|
|
||||||
stop_composer()
|
|
||||||
|
@ -56,6 +56,9 @@ BASE_DIR = Path(__file__).parent.parent.resolve()
|
|||||||
PROCFILE_RUNSERVER = env.str("PROCFILE_RUNSERVER", None)
|
PROCFILE_RUNSERVER = env.str("PROCFILE_RUNSERVER", None)
|
||||||
PROCFILE_PYTEST = env.str("PROCFILE_PYTEST", None)
|
PROCFILE_PYTEST = env.str("PROCFILE_PYTEST", None)
|
||||||
|
|
||||||
|
## File path used to avoid running the composer multiple times at the same time
|
||||||
|
COMPOSER_PID_PATH = env.path("COMPOSER_PID_PATH", BASE_DIR / "composer.pid")
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user