-
Notifications
You must be signed in to change notification settings - Fork 94
Expand file tree
/
Copy pathmain.py
More file actions
156 lines (127 loc) · 5.15 KB
/
main.py
File metadata and controls
156 lines (127 loc) · 5.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import logging
import os
import threading
from contextlib import asynccontextmanager
from fastapi import FastAPI
from api.api_schemas import AppStatus
from api.middleware import InitializationMiddleware
from api.routes import health, metrics
from managers.app_state_manager import AppStateManager
from managers.pipeline_manager import PipelineManager
from managers.pipeline_template_manager import PipelineTemplateManager
from videos import VideosManager
# Configure logging
handler = logging.StreamHandler()
handler.setFormatter(
logging.Formatter(
fmt="%(asctime)s %(levelname)s %(name)s %(message)s",
datefmt="%Y-%m-%dT%H:%M:%SZ",
)
)
for logger_name in ("uvicorn", "uvicorn.error", "uvicorn.access"):
logger = logging.getLogger(logger_name)
logger.setLevel(os.environ.get("WEB_SERVER_LOG_LEVEL", "WARNING").upper())
logger.handlers.clear()
logger.handlers = [handler]
logger.propagate = False
logger = logging.getLogger()
logger.setLevel(os.environ.get("LOG_LEVEL", "INFO").upper())
logger.handlers = [handler]
def _initialize_in_background(app: FastAPI) -> None:
"""
Initialize application resources in background thread.
This function runs in a separate thread so the server can start
responding to health checks immediately while initialization proceeds.
"""
app_state_manager = AppStateManager()
try:
app_state_manager.set_status(
AppStatus.INITIALIZING, "Downloading videos and loading metadata..."
)
# Initialize VideosManager - downloads videos, scans files,
# extracts metadata, and converts to TS format
VideosManager()
# Initialize PipelineManager - loads predefined pipelines
PipelineManager()
# Initialize PipelineTemplateManager - loads pipeline templates
PipelineTemplateManager()
# Register remaining routers after VideosManager and PipelineManager are initialized
register_routers(app)
app_state_manager.set_status(AppStatus.READY)
logger.info("Application initialization complete")
except Exception as e:
logger.error(f"Failed to initialize application: {e}")
app_state_manager.set_status(AppStatus.SHUTDOWN, f"Initialization failed: {e}")
def register_routers(app: FastAPI) -> None:
"""
Register all API routers (except health which is registered early).
This function is called after VideosManager initialization to avoid
importing modules that depend on VideosManager before it's initialized.
"""
# Import routers here to avoid early initialization of VideosManager
from api.routes import (
convert,
devices,
jobs,
models,
pipeline_templates,
pipelines,
tests,
videos,
cameras,
)
# Include routers from different modules
app.include_router(convert.router, prefix="/convert", tags=["convert"])
app.include_router(devices.router, prefix="/devices", tags=["devices"])
app.include_router(jobs.router, prefix="/jobs", tags=["jobs"])
app.include_router(models.router, prefix="/models", tags=["models"])
app.include_router(
pipeline_templates.router,
prefix="/pipeline-templates",
tags=["pipeline-templates"],
)
app.include_router(pipelines.router, prefix="/pipelines", tags=["pipelines"])
app.include_router(tests.router, prefix="/tests", tags=["tests"])
app.include_router(videos.router, prefix="/videos", tags=["videos"])
app.include_router(cameras.router, prefix="/cameras", tags=["cameras"])
@asynccontextmanager
async def lifespan(app: FastAPI):
"""
FastAPI lifespan context manager for startup and shutdown.
Starts initialization in background thread so server can respond
to health checks immediately.
"""
logger.info("Application starting...")
app_state_manager = AppStateManager()
app_state_manager.set_status(AppStatus.STARTING)
# Start initialization in background thread
init_thread = threading.Thread(
target=_initialize_in_background,
args=(app,),
name="initialization-thread",
daemon=True,
)
init_thread.start()
yield
# Shutdown
logger.info("Application shutting down...")
app_state_manager.set_status(AppStatus.SHUTDOWN)
# Initialize FastAPI app with lifespan
app = FastAPI(
title="Visual Pipeline and Platform Evaluation Tool API",
description="API for Visual Pipeline and Platform Evaluation Tool",
version="1.0.0",
root_path="/api/v1",
# without explicitly setting servers to the same value as root_path,
# generating openapi schema would omit whole servers section in vippet.json
servers=[
{"url": "/api/v1"},
],
lifespan=lifespan,
)
# Add middleware to block requests during initialization
app.add_middleware(InitializationMiddleware)
# Register health router immediately (before initialization) so health checks work while app is initializing
app.include_router(health.router, tags=["health"])
# Register metrics router immediately (it does not depend on VideosManager) so collector can connect as soon as possible
app.include_router(metrics.router, prefix="/metrics", tags=["metrics"])