Coverage for src/app.py: 0%
54 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-06-23 04:49 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-06-23 04:49 +0000
1import logging
2import signal
3import sys
4from os import environ
5from tempfile import TemporaryDirectory
7# these two lines need to be at the top of the file before we span child processes
8# this temp dir will be destroyed when prometheus_multiproc_dir is destroyed, aka at the end of the program
9prometheus_multiproc_dir = TemporaryDirectory()
10environ["PROMETHEUS_MULTIPROC_DIR"] = prometheus_multiproc_dir.name
11# ruff: noqa: E402
13import sentry_sdk
14from sentry_sdk.integrations import argv, atexit, dedupe, modules, stdlib, threading
15from sentry_sdk.integrations import logging as sentry_logging
16from sqlalchemy.sql import text
18from couchers.config import check_config, config
19from couchers.db import apply_migrations, session_scope
20from couchers.jobs.worker import start_jobs_scheduler, start_jobs_worker
21from couchers.metrics import create_prometheus_server
22from couchers.server import create_main_server, create_media_server
23from couchers.tracing import setup_tracing
24from dummy_data import add_dummy_data
26check_config()
28logging.basicConfig(
29 format="[%(process)5d:%(thread)20d] %(asctime)s: %(name)s:%(lineno)d: %(message)s", level=logging.INFO
30)
31logger = logging.getLogger(__name__)
33if config["SENTRY_ENABLED"]:
34 # Sends exception tracebacks to Sentry, a cloud service for collecting exceptions
35 sentry_sdk.init(
36 config["SENTRY_URL"],
37 traces_sample_rate=0.0,
38 environment=config["COOKIE_DOMAIN"],
39 release=config["VERSION"],
40 default_integrations=False,
41 integrations=[
42 # we need to manually list out the integrations, there is no other way of disabling the global excepthook integration
43 # we want to disable that because it seems to be picking up already handled gRPC errors (e.g. grpc.StatusCode.NOT_FOUND)
44 argv.ArgvIntegration(),
45 atexit.AtexitIntegration(),
46 dedupe.DedupeIntegration(),
47 sentry_logging.LoggingIntegration(),
48 modules.ModulesIntegration(),
49 stdlib.StdlibIntegration(),
50 threading.ThreadingIntegration(),
51 ],
52 )
54# used to export metrics
55create_prometheus_server(8000)
58def log_unhandled_exception(exc_type, exc_value, exc_traceback):
59 """Make sure that any unhandled exceptions will write to the logs"""
60 if issubclass(exc_type, KeyboardInterrupt):
61 # call the default excepthook saved at __excepthook__
62 sys.__excepthook__(exc_type, exc_value, exc_traceback)
63 return
64 logger.critical("Unhandled exception", exc_info=(exc_type, exc_value, exc_traceback))
67sys.excepthook = log_unhandled_exception
69logger.info("Checking DB connection")
71with session_scope() as session:
72 res = session.execute(text("SELECT 42;"))
73 if list(res) != [(42,)]:
74 raise Exception("Failed to connect to DB")
76logger.info("Running DB migrations")
78apply_migrations()
80if config["ADD_DUMMY_DATA"]:
81 add_dummy_data()
83logger.info("Starting")
85if config["ROLE"] in ["scheduler", "all"]:
86 scheduler = start_jobs_scheduler()
88if config["ROLE"] in ["worker", "all"]:
89 for _ in range(config["BACKGROUND_WORKER_COUNT"]):
90 start_jobs_worker()
92setup_tracing()
94if config["ROLE"] in ["api", "all"]:
95 server = create_main_server(port=1751)
96 server.start()
97 media_server = create_media_server(port=1753)
98 media_server.start()
99 logger.info("Serving on 1751 (secure) and 1753 (media)")
101logger.info("App waiting for signal...")
103signal.pause()