generated from root/feiqiu-ETL
正式起服务打底
This commit is contained in:
BIN
app/__pycache__/config.cpython-313.pyc
Normal file
BIN
app/__pycache__/config.cpython-313.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/db.cpython-313.pyc
Normal file
BIN
app/__pycache__/db.cpython-313.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/main.cpython-313.pyc
Normal file
BIN
app/__pycache__/main.cpython-313.pyc
Normal file
Binary file not shown.
48
app/config.py
Normal file
48
app/config.py
Normal file
@@ -0,0 +1,48 @@
|
||||
# app/config.py
|
||||
import os
|
||||
from functools import lru_cache
|
||||
|
||||
|
||||
class Settings:
|
||||
"""
|
||||
后端配置:
|
||||
- APP_ENV: dev / prod
|
||||
- DB_*: 数据库连接参数
|
||||
- 默认库:dev 用 LLZQ-test;prod 用 LLZQ
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.app_env = os.getenv("APP_ENV", "dev").lower()
|
||||
|
||||
self.db_host = os.getenv("DB_HOST", "127.0.0.1")
|
||||
self.db_port = int(os.getenv("DB_PORT", "5432"))
|
||||
self.db_user = os.getenv("DB_USER", "local-Python")
|
||||
self.db_password = os.getenv("DB_PASSWORD", "")
|
||||
|
||||
# 默认连接的库,根据 APP_ENV 决定
|
||||
if self.app_env == "prod":
|
||||
self.db_name_default = "LLZQ"
|
||||
else:
|
||||
self.db_name_default = "LLZQ-test"
|
||||
|
||||
self.db_schema = os.getenv("DB_SCHEMA", "XCX")
|
||||
|
||||
def resolve_db_name(self, env_header: str | None) -> str:
|
||||
"""
|
||||
根据前端传来的 X-LLZQ-Env 决定最终使用哪个 DB:
|
||||
- "prod" => LLZQ
|
||||
- 其它/为空 => LLZQ-test
|
||||
"""
|
||||
if env_header is None:
|
||||
return self.db_name_default
|
||||
|
||||
env_header = env_header.lower()
|
||||
if env_header == "prod":
|
||||
return "LLZQ"
|
||||
else:
|
||||
return "LLZQ-test"
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def get_settings() -> Settings:
|
||||
return Settings()
|
||||
42
app/db.py
Normal file
42
app/db.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# app/db.py
|
||||
from contextlib import contextmanager
|
||||
from typing import Iterator
|
||||
|
||||
import psycopg2
|
||||
from psycopg2.extras import RealDictCursor
|
||||
|
||||
from .config import get_settings
|
||||
|
||||
|
||||
@contextmanager
|
||||
def get_connection(db_name: str) -> Iterator[psycopg2.extensions.connection]:
|
||||
"""
|
||||
简单连接管理:每次请求开一个连接,用完就关。
|
||||
当前访问量不高,这种写法足够。
|
||||
"""
|
||||
settings = get_settings()
|
||||
conn = psycopg2.connect(
|
||||
host=settings.db_host,
|
||||
port=settings.db_port,
|
||||
user=settings.db_user,
|
||||
password=settings.db_password,
|
||||
dbname=db_name,
|
||||
)
|
||||
try:
|
||||
# 设置 schema = XCX
|
||||
with conn.cursor() as cur:
|
||||
cur.execute("SET search_path TO %s;", (settings.db_schema,))
|
||||
yield conn
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def check_health(db_name: str) -> bool:
|
||||
"""
|
||||
DB 健康检查:SELECT 1
|
||||
"""
|
||||
with get_connection(db_name) as conn:
|
||||
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
||||
cur.execute("SELECT 1 AS v;")
|
||||
row = cur.fetchone()
|
||||
return row["v"] == 1
|
||||
51
app/main.py
Normal file
51
app/main.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# app/main.py
|
||||
from fastapi import FastAPI, Header, Depends
|
||||
|
||||
from .config import get_settings
|
||||
from .db import check_health
|
||||
|
||||
app = FastAPI(
|
||||
title="LLZQ Backend",
|
||||
version="0.1.0",
|
||||
)
|
||||
|
||||
|
||||
def resolve_db_name(x_llzq_env: str | None = Header(default=None, alias="X-LLZQ-Env")) -> str:
|
||||
"""
|
||||
从请求头 X-LLZQ-Env 中解析要用的 DB 名。
|
||||
"""
|
||||
settings = get_settings()
|
||||
return settings.resolve_db_name(x_llzq_env)
|
||||
|
||||
|
||||
@app.get("/api/ping")
|
||||
def ping(db_name: str = Depends(resolve_db_name)):
|
||||
"""
|
||||
最简单调通接口:
|
||||
- 返回当前后端环境
|
||||
- 返回实际连接的 DB 名
|
||||
- 简单做一个 DB 健康检查
|
||||
"""
|
||||
settings = get_settings()
|
||||
ok = False
|
||||
error_msg = None
|
||||
|
||||
try:
|
||||
ok = check_health(db_name)
|
||||
except Exception as e:
|
||||
error_msg = str(e)
|
||||
|
||||
return {
|
||||
"ok": ok,
|
||||
"app_env": settings.app_env,
|
||||
"db": db_name,
|
||||
"error": error_msg,
|
||||
}
|
||||
|
||||
|
||||
@app.get("/api/healthz")
|
||||
def healthz():
|
||||
"""
|
||||
给 Nginx / 监控用的探活接口,不查 DB。
|
||||
"""
|
||||
return {"status": "ok"}
|
||||
1
logs/llzq_api_8000.0.err.log
Normal file
1
logs/llzq_api_8000.0.err.log
Normal file
@@ -0,0 +1 @@
|
||||
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
|
||||
1
logs/llzq_api_8000.0.out.log
Normal file
1
logs/llzq_api_8000.0.out.log
Normal file
@@ -0,0 +1 @@
|
||||
INFO: 100.64.0.1:59692 - "GET /api/ping HTTP/1.1" 200 OK
|
||||
1
logs/llzq_api_8000.1.err.log
Normal file
1
logs/llzq_api_8000.1.err.log
Normal file
@@ -0,0 +1 @@
|
||||
INFO: Application startup complete.
|
||||
1
logs/llzq_api_8000.1.out.log
Normal file
1
logs/llzq_api_8000.1.out.log
Normal file
@@ -0,0 +1 @@
|
||||
INFO: 100.64.0.1:59690 - "GET /api/healthz HTTP/1.1" 200 OK
|
||||
1
logs/llzq_api_8000.2.err.log
Normal file
1
logs/llzq_api_8000.2.err.log
Normal file
@@ -0,0 +1 @@
|
||||
INFO: Waiting for application startup.
|
||||
1
logs/llzq_api_8000.2.out.log
Normal file
1
logs/llzq_api_8000.2.out.log
Normal file
@@ -0,0 +1 @@
|
||||
INFO: 100.64.0.1:60268 - "GET /api/ping HTTP/1.1" 200 OK
|
||||
1
logs/llzq_api_8000.3.err.log
Normal file
1
logs/llzq_api_8000.3.err.log
Normal file
@@ -0,0 +1 @@
|
||||
INFO: Started server process [11432]
|
||||
1
logs/llzq_api_8000.3.out.log
Normal file
1
logs/llzq_api_8000.3.out.log
Normal file
@@ -0,0 +1 @@
|
||||
INFO: 100.64.0.1:60266 - "GET /api/healthz HTTP/1.1" 200 OK
|
||||
1
logs/llzq_api_8000.4.out.log
Normal file
1
logs/llzq_api_8000.4.out.log
Normal file
@@ -0,0 +1 @@
|
||||
INFO: 127.0.0.1:56463 - "GET /api/ping HTTP/1.1" 200 OK
|
||||
1
logs/llzq_api_8000.5.out.log
Normal file
1
logs/llzq_api_8000.5.out.log
Normal file
@@ -0,0 +1 @@
|
||||
INFO: 127.0.0.1:56463 - "GET /api/healthz HTTP/1.1" 200 OK
|
||||
0
logs/llzq_api_8000.err.log
Normal file
0
logs/llzq_api_8000.err.log
Normal file
0
logs/llzq_api_8000.out.log
Normal file
0
logs/llzq_api_8000.out.log
Normal file
11
logs/llzq_api_8000.wrapper.log
Normal file
11
logs/llzq_api_8000.wrapper.log
Normal file
@@ -0,0 +1,11 @@
|
||||
2025-11-19 04:51:16,714 DEBUG - Starting WinSW in console mode
|
||||
2025-11-19 04:51:16,728 INFO - Installing service 'LLZQ API (FastAPI 8000) (llzq-api-8000)'...
|
||||
2025-11-19 04:51:16,755 INFO - Service 'LLZQ API (FastAPI 8000) (llzq-api-8000)' was installed successfully.
|
||||
2025-11-19 04:51:16,909 DEBUG - Starting WinSW in console mode
|
||||
2025-11-19 04:51:16,925 INFO - Starting service 'LLZQ API (FastAPI 8000) (llzq-api-8000)'...
|
||||
2025-11-19 04:51:17,008 DEBUG - Starting WinSW in service mode
|
||||
2025-11-19 04:51:17,017 INFO - Service 'LLZQ API (FastAPI 8000) (llzq-api-8000)' started successfully.
|
||||
2025-11-19 04:51:17,024 INFO - Starting D:\LLZQ\LLZQ-server\.venv\Scripts\uvicorn.exe app.main:app --host 0.0.0.0 --port 8000
|
||||
2025-11-19 04:51:17,041 INFO - Started process 10844
|
||||
2025-11-19 04:51:17,047 DEBUG - Forwarding logs of the process System.Diagnostics.Process (uvicorn) to WinSW.SizeBasedRollingLogAppender
|
||||
2025-11-19 04:51:18,533 DEBUG - Starting WinSW in console mode
|
||||
Reference in New Issue
Block a user