-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathapp.py
More file actions
84 lines (65 loc) · 2.97 KB
/
app.py
File metadata and controls
84 lines (65 loc) · 2.97 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
import logging
import os
from typing import Any
import wireup.integration.flask
from asgiref.wsgi import WsgiToAsgi
from aws_xray_sdk.core import patch_all
from flask import Flask
from mangum import Mangum
from mangum.types import LambdaContext, LambdaEvent
from eligibility_signposting_api import audit, repos, services
from eligibility_signposting_api.common.cache_manager import FLASK_APP_CACHE_KEY, cache_manager
from eligibility_signposting_api.common.error_handler import handle_exception
from eligibility_signposting_api.config.config import config
from eligibility_signposting_api.config.constants import URL_PREFIX
from eligibility_signposting_api.logging.logs_helper import log_request_ids_from_headers
from eligibility_signposting_api.logging.logs_manager import add_lambda_request_id_to_logger, init_logging
from eligibility_signposting_api.logging.tracing_helper import tracing_setup
from eligibility_signposting_api.middleware import SecurityHeadersMiddleware
from eligibility_signposting_api.views import eligibility_blueprint
if os.getenv("ENABLE_XRAY_PATCHING"):
patch_all()
init_logging()
logger = logging.getLogger(__name__)
def main() -> None: # pragma: no cover
"""Run the Flask app as a local process."""
app = create_app()
app.run(debug=config()["log_level"] == logging.DEBUG)
def get_or_create_app() -> Flask:
"""Get the global Flask app instance, creating it if it doesn't exist.
This ensures the Flask app is initialized only once per Lambda container,
improving performance by avoiding repeated initialization.
"""
app = cache_manager.get(FLASK_APP_CACHE_KEY)
if app is None:
app = create_app()
cache_manager.set(FLASK_APP_CACHE_KEY, app)
logger.info("Flask app initialized and cached for container reuse")
return app # type: ignore[return-value]
@add_lambda_request_id_to_logger()
@tracing_setup()
@log_request_ids_from_headers()
def lambda_handler(event: LambdaEvent, context: LambdaContext) -> dict[str, Any]: # pragma: no cover
"""Run the Flask app as an AWS Lambda."""
app = get_or_create_app()
app.debug = config()["log_level"] == logging.DEBUG
handler = Mangum(WsgiToAsgi(app), lifespan="off")
handler.config["text_mime_types"].append("application/fhir+json")
return handler(event, context)
def create_app() -> Flask:
app = Flask(__name__)
logger.info("app created")
# Register security headers middleware
SecurityHeadersMiddleware(app)
# Register views & error handler
app.register_blueprint(eligibility_blueprint, url_prefix=f"/{URL_PREFIX}")
app.register_error_handler(Exception, handle_exception)
# Set up dependency injection using wireup
container = wireup.create_sync_container(
service_modules=[services, repos, audit], parameters={**app.config, **config()}
)
wireup.integration.flask.setup(container, app)
logger.info("app ready", extra={"config": {**app.config, **config()}})
return app
if __name__ == "__main__":
main()