refactor(api): TOML 配置 SSOT、统一错误契约、Auth/事务加固与可观测性 (#33)

配置 SSOT(TOML + .env)
统一错误契约
Auth 与事务边界
Redis / Celery 可靠性:业务 Redis(DB/0)与 Celery broker/backend(DB/1)显式拆分;连接池、sync client
可观测性(OpenTelemetry + LGTM)
This commit is contained in:
Sully
2026-05-22 13:44:50 +08:00
committed by GitHub
parent f09ae248f9
commit 53e0065e3e
298 changed files with 15247 additions and 4344 deletions

View File

@@ -17,13 +17,15 @@ from sqlalchemy.orm import Session
from app.agents.memoir.narrative_agent import NarrativeAgent
from app.core.config import settings
from app.core.db import get_sync_db
from app.core.db import get_sync_db, transactional_sync
from app.core.llm_gateway import LlmGateway, LlmUseCase
from app.core.logging import get_logger
from app.core.memoir_pipeline_progress import merge_pipeline_run
from app.features.memoir.models import Chapter
from app.features.memoir.repo import mark_chapter_dirty_sync
from app.features.story.models import Story
from app.features.memoir.constants import memoir
from app.features.story.constants import story
logger = get_logger(__name__)
@@ -54,7 +56,7 @@ def _polish_story_title(
return False
body = (story.canonical_markdown or "").strip()
if len(body) < settings.story_title_min_body_chars:
if len(body) < story.title_min_body_chars:
return False
narrative_agent = NarrativeAgent()
@@ -76,7 +78,7 @@ def _polish_story_title(
return True
@shared_task(bind=True, max_retries=2, default_retry_delay=30)
@shared_task(bind=True, max_retries=2, default_retry_delay=30, ignore_result=True)
def memoir_quality_pass(
self,
user_id: str,
@@ -89,7 +91,7 @@ def memoir_quality_pass(
Runs asynchronously after the fast draft is committed and visible.
"""
qptid = str(self.request.id)
if not settings.memoir_quality_pass_enabled:
if not memoir.quality_pass_enabled:
if memoir_correlation_id:
merge_pipeline_run(
memoir_correlation_id,
@@ -152,34 +154,32 @@ def memoir_quality_pass(
== "en"
else "zh"
)
for sid in story_ids:
story = db.get(Story, sid)
if not story or story.user_id != user_id:
continue
with transactional_sync(db):
for sid in story_ids:
story = db.get(Story, sid)
if not story or story.user_id != user_id:
continue
chapter_category = story.stage or "summary"
if _polish_story_title(
db,
story,
llm,
chapter_category=chapter_category,
language=user_language,
):
titles_polished += 1
stmt = select(Chapter.id).where(
Chapter.user_id == user_id,
Chapter.category == chapter_category,
Chapter.is_active == True, # noqa: E712
)
ch_id = db.execute(stmt).scalar_one_or_none()
if ch_id:
chapters_dirtied.add(str(ch_id))
chapter_category = story.stage or "summary"
if _polish_story_title(
db,
story,
llm,
chapter_category=chapter_category,
language=user_language,
):
titles_polished += 1
stmt = select(Chapter.id).where(
Chapter.user_id == user_id,
Chapter.category == chapter_category,
Chapter.is_active == True, # noqa: E712
)
ch_id = db.execute(stmt).scalar_one_or_none()
if ch_id:
chapters_dirtied.add(str(ch_id))
for ch_id in chapters_dirtied:
mark_chapter_dirty_sync(db, ch_id)
if titles_polished > 0:
db.commit()
for ch_id in chapters_dirtied:
mark_chapter_dirty_sync(db, ch_id)
elapsed = time.perf_counter() - t0
duration_ms = elapsed * 1000