Source code for camcops_server.camcops_windows_service
"""
camcops_server/camcops_windows_service.py
===============================================================================
Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
This file is part of CamCOPS.
CamCOPS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CamCOPS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
===============================================================================
**Run CamCOPS and its associated back-end tools as a Windows service.**
"""
import os
import logging
import sys
from cardinal_pythonlib.winservice import (
ProcessDetails,
generic_service_main,
WindowsService,
)
from camcops_server.cc_modules.cc_baseconstants import ENVVAR_CONFIG_FILE
log = logging.getLogger(__name__)
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
WINSERVICE_LOGDIR_ENVVAR = "CAMCOPS_WINSERVICE_LOGDIR"
# =============================================================================
# Windows service framework
# =============================================================================
[docs]class CamcopsWinService(WindowsService):
"""
Windows service class for CamCOPS.
"""
# you can NET START/STOP the service by the following name
_svc_name_ = "CamCOPS"
# this text shows up as the service name in the Service
# Control Manager (SCM)
_svc_display_name_ = "CamCOPS service"
# this text shows up as the description in the SCM
_svc_description_ = (
"Runs web server, scheduler, and worker processes for CamCOPS"
)
# how to launch?
_exe_name_ = sys.executable # python.exe in the virtualenv
_exe_args_ = f'"{os.path.realpath(__file__)}"' # this script
# -------------------------------------------------------------------------
# The service
# -------------------------------------------------------------------------
[docs] def service(self) -> None:
"""
Run the Windows service.
- Reads the log directory from the environment variable
``CAMCOPS_WINSERVICE_LOGDIR``.
- Checks that the environment variable ``CAMCOPS_CONFIG_FILE`` is set.
- Launches the CherryPy web server.
- Launches the Celery scheduler.
- Launches the Celery workers.
"""
# Read from environment
try:
logdir = os.environ[WINSERVICE_LOGDIR_ENVVAR]
except KeyError:
raise ValueError(
f"Must specify {WINSERVICE_LOGDIR_ENVVAR} "
f"system environment variable"
)
if ENVVAR_CONFIG_FILE not in os.environ:
raise ValueError(
f"Must specify {ENVVAR_CONFIG_FILE} "
f"system environment variable"
)
# Define processes
camcops_server = os.path.join(CURRENT_DIR, "camcops_server.py")
weblog = os.path.join(logdir, "camcops_webserver.log")
schedulerlog = os.path.join(logdir, "camcops_scheduler.log")
workerlog = os.path.join(logdir, "camcops_workers.log")
procdetails = [
ProcessDetails(
name="CherryPy web server",
procargs=[sys.executable, camcops_server, "serve_cherrypy"],
logfile_out=weblog,
logfile_err=weblog,
),
ProcessDetails(
name="Celery scheduler",
procargs=[sys.executable, camcops_server, "launch_scheduler"],
logfile_out=schedulerlog,
logfile_err=schedulerlog,
),
ProcessDetails(
name="Celery workers",
procargs=[sys.executable, camcops_server, "launch_workers"],
logfile_out=workerlog,
logfile_err=workerlog,
),
]
# Run processes
self.run_processes(procdetails)
# =============================================================================
# Main
# =============================================================================
[docs]def main():
"""
Command-line entry point.
"""
# Called as an entry point (see setup.py).
logging.basicConfig(level=logging.DEBUG)
generic_service_main(CamcopsWinService, "CamcopsWinService")
if __name__ == "__main__":
main()