docs(README): 更新项目说明文档,完善架构与启动指南
- 调整 CLAUDE.md 内容,增加使用指导和架构概览 - 补充微服务启动说明及单服务启动命令 - 明确 Gateway 服务器四阶段启动流程和职责划分 - 细化后端目录结构说明,补充主要文件职责描述 - 新增系统分层结构图,优化整体架构理解 - 更新 .gitignore,添加 runs 目录忽略规则 - 同步 .omc 相关状态文件,更新项目状态跟踪信息
This commit is contained in:
@@ -41,6 +41,8 @@ class SkillsManager:
|
||||
)
|
||||
self.runs_root = self.project_root / "runs"
|
||||
self._lock = Lock()
|
||||
# Instance-level pending skill changes (thread-safe via self._lock)
|
||||
self._pending_skill_changes: Dict[str, Set[Path]] = {}
|
||||
|
||||
def get_active_root(self, config_name: str) -> Path:
|
||||
return self.runs_root / config_name / "skills" / "active"
|
||||
@@ -739,7 +741,7 @@ class SkillsManager:
|
||||
if local_root.exists():
|
||||
watched_paths.append(local_root)
|
||||
|
||||
handler = _SkillsChangeHandler(watched_paths, callback, self._lock)
|
||||
handler = _SkillsChangeHandler(watched_paths, self._pending_skill_changes, callback, self._lock)
|
||||
observer = Observer()
|
||||
for path in watched_paths:
|
||||
observer.schedule(handler, str(path), recursive=True)
|
||||
@@ -773,6 +775,7 @@ class SkillsManager:
|
||||
# -------------------------------------------------------------------------
|
||||
# Internal change-tracking state (populated by _SkillsChangeHandler)
|
||||
# -------------------------------------------------------------------------
|
||||
# Legacy class-level reference kept for migration compatibility
|
||||
_pending_skill_changes: Dict[str, Set[Path]] = {}
|
||||
|
||||
def _resolve_disabled_skill_names(
|
||||
@@ -824,11 +827,13 @@ class _SkillsChangeHandler(FileSystemEventHandler):
|
||||
def __init__(
|
||||
self,
|
||||
watched_paths: List[Path],
|
||||
pending_changes: Dict[str, Set[Path]],
|
||||
callback: Optional[Any] = None,
|
||||
lock: Optional[Lock] = None,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self._watched_paths = watched_paths
|
||||
self._pending_changes = pending_changes
|
||||
self._callback = callback
|
||||
self._lock = lock
|
||||
|
||||
@@ -841,13 +846,9 @@ class _SkillsChangeHandler(FileSystemEventHandler):
|
||||
run_id = self._run_id_from_path(src_path)
|
||||
if self._lock:
|
||||
with self._lock:
|
||||
SkillsManager._pending_skill_changes.setdefault(
|
||||
run_id, set()
|
||||
).add(src_path)
|
||||
self._pending_changes.setdefault(run_id, set()).add(src_path)
|
||||
else:
|
||||
SkillsManager._pending_skill_changes.setdefault(
|
||||
run_id, set()
|
||||
).add(src_path)
|
||||
self._pending_changes.setdefault(run_id, set()).add(src_path)
|
||||
if self._callback:
|
||||
self._callback([src_path])
|
||||
break
|
||||
|
||||
@@ -9,6 +9,7 @@ from .runtime_service import app as runtime_app
|
||||
from .runtime_service import create_app as create_runtime_app
|
||||
from .trading_service import app as trading_app
|
||||
from .trading_service import create_app as create_trading_app
|
||||
from .cors import add_cors_middleware, get_cors_origins
|
||||
|
||||
app = agent_app
|
||||
create_app = create_agent_app
|
||||
@@ -24,4 +25,6 @@ __all__ = [
|
||||
"create_runtime_app",
|
||||
"trading_app",
|
||||
"create_trading_app",
|
||||
"add_cors_middleware",
|
||||
"get_cors_origins",
|
||||
]
|
||||
|
||||
@@ -8,7 +8,8 @@ from pathlib import Path
|
||||
from typing import AsyncGenerator
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
from backend.apps.cors import add_cors_middleware
|
||||
|
||||
from backend.api import agents_router, guard_router, workspaces_router
|
||||
from backend.agents import AgentFactory, WorkspaceManager, get_registry
|
||||
@@ -47,13 +48,7 @@ def create_app(project_root: Path | None = None) -> FastAPI:
|
||||
lifespan=lifespan,
|
||||
)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
add_cors_middleware(app)
|
||||
|
||||
@app.get("/health")
|
||||
async def health_check() -> dict[str, object]:
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
from backend.api import runtime_router
|
||||
from backend.api.runtime import get_runtime_state
|
||||
from backend.apps.cors import add_cors_middleware
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
@@ -18,13 +18,7 @@ def create_app() -> FastAPI:
|
||||
version="0.1.0",
|
||||
)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
add_cors_middleware(app)
|
||||
|
||||
@app.get("/health")
|
||||
async def health_check() -> dict[str, object]:
|
||||
|
||||
@@ -6,7 +6,7 @@ from __future__ import annotations
|
||||
from typing import Any
|
||||
|
||||
from fastapi import FastAPI, Query
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from backend.apps.cors import add_cors_middleware
|
||||
|
||||
from backend.domains import trading as trading_domain
|
||||
from shared.schema import (
|
||||
@@ -26,13 +26,7 @@ def create_app() -> FastAPI:
|
||||
version="0.1.0",
|
||||
)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
add_cors_middleware(app)
|
||||
|
||||
@app.get("/health")
|
||||
async def health_check() -> dict[str, str]:
|
||||
|
||||
@@ -266,10 +266,6 @@ async def run_pipeline(
|
||||
|
||||
set_global_runtime_manager(runtime_manager)
|
||||
|
||||
# Register runtime manager with API
|
||||
from backend.api.runtime import register_runtime_manager
|
||||
register_runtime_manager(runtime_manager)
|
||||
|
||||
# ======================================================================
|
||||
# PHASE 1 & 2: Create infrastructure services (Market, Storage)
|
||||
# These will be started by Gateway in the correct order
|
||||
|
||||
@@ -9,7 +9,7 @@ import os
|
||||
import sqlite3
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any, Iterable
|
||||
from typing import Any, Iterable, Optional
|
||||
|
||||
|
||||
SCHEMA = """
|
||||
@@ -147,12 +147,30 @@ def _utc_timestamp() -> str:
|
||||
|
||||
|
||||
class MarketStore:
|
||||
"""SQLite-backed market research warehouse."""
|
||||
"""SQLite-backed market research warehouse. Use get_instance() for the singleton."""
|
||||
|
||||
_instance: Optional["MarketStore"] = None
|
||||
|
||||
def __new__(cls, db_path: Path | None = None) -> "MarketStore":
|
||||
if cls._instance is not None:
|
||||
if db_path is None or cls._instance.db_path == Path(db_path or get_market_db_path()):
|
||||
return cls._instance
|
||||
instance = super().__new__(cls)
|
||||
cls._instance = instance
|
||||
return instance
|
||||
|
||||
def __init__(self, db_path: Path | None = None):
|
||||
if getattr(self, "_initialized", False):
|
||||
return
|
||||
self.db_path = Path(db_path or get_market_db_path())
|
||||
self.db_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
self._init_db()
|
||||
self._initialized = True
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls, db_path: Path | None = None) -> "MarketStore":
|
||||
"""Get the MarketStore singleton instance."""
|
||||
return cls(db_path)
|
||||
|
||||
def _connect(self) -> sqlite3.Connection:
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
|
||||
@@ -226,7 +226,6 @@ async def run_with_gateway(args):
|
||||
)
|
||||
runtime_manager.prepare_run()
|
||||
set_global_runtime_manager(runtime_manager)
|
||||
register_runtime_manager(runtime_manager)
|
||||
|
||||
# Create market service
|
||||
market_service = MarketService(
|
||||
|
||||
@@ -13,15 +13,30 @@ from .registry import RuntimeRegistry
|
||||
_global_runtime_manager: Optional["TradingRuntimeManager"] = None
|
||||
_shutdown_event: Optional[asyncio.Event] = None
|
||||
|
||||
# Lazy import to avoid circular dependency
|
||||
_api_runtime = None
|
||||
|
||||
|
||||
def _get_api_runtime():
|
||||
global _api_runtime
|
||||
if _api_runtime is None:
|
||||
from backend.api import runtime as api_runtime_module
|
||||
_api_runtime = api_runtime_module
|
||||
return _api_runtime
|
||||
|
||||
|
||||
def set_global_runtime_manager(manager: "TradingRuntimeManager") -> None:
|
||||
global _global_runtime_manager
|
||||
_global_runtime_manager = manager
|
||||
# Sync to RuntimeState for consistency
|
||||
_get_api_runtime().register_runtime_manager(manager)
|
||||
|
||||
|
||||
def clear_global_runtime_manager() -> None:
|
||||
global _global_runtime_manager
|
||||
_global_runtime_manager = None
|
||||
# Sync to RuntimeState for consistency
|
||||
_get_api_runtime().unregister_runtime_manager()
|
||||
|
||||
|
||||
def get_global_runtime_manager() -> Optional["TradingRuntimeManager"]:
|
||||
|
||||
Reference in New Issue
Block a user