Spaces:
Running on Zero
Running on Zero
| """ | |
| main.py — Application entrypoint. | |
| Starts: | |
| 1. FastAPI app (HTTP + WebSocket) | |
| 2. APScheduler background job for offline consolidation | |
| The consolidation job is fully offline/scheduled — it does NOT run during episodes. | |
| Parallel episodes do NOT see each other's lesson writes mid-batch (per §8.1). | |
| """ | |
| from __future__ import annotations | |
| import asyncio | |
| import os | |
| import sys | |
| import structlog | |
| import uvicorn | |
| from apscheduler.schedulers.asyncio import AsyncIOScheduler | |
| from config import settings | |
| from memory.consolidate import run_consolidation | |
| from server.app import app | |
| log = structlog.get_logger(__name__) | |
| def setup_logging() -> None: | |
| structlog.configure( | |
| processors=[ | |
| structlog.contextvars.merge_contextvars, | |
| structlog.processors.TimeStamper(fmt="iso"), | |
| structlog.stdlib.add_log_level, | |
| structlog.dev.ConsoleRenderer(), | |
| ], | |
| wrapper_class=structlog.stdlib.BoundLogger, | |
| context_class=dict, | |
| logger_factory=structlog.PrintLoggerFactory(), | |
| ) | |
| async def consolidation_job() -> None: | |
| """Wrapper for the APScheduler async job.""" | |
| try: | |
| stats = await run_consolidation() | |
| log.info("scheduler.consolidation_complete", **stats) | |
| except Exception as exc: | |
| log.exception("scheduler.consolidation_error", error=str(exc)) | |
| def main() -> None: | |
| setup_logging() | |
| # Set up APScheduler for offline consolidation | |
| scheduler = AsyncIOScheduler() | |
| scheduler.add_job( | |
| consolidation_job, | |
| "interval", | |
| minutes=settings.consolidation_interval_minutes, | |
| id="consolidation", | |
| replace_existing=True, | |
| ) | |
| log.info( | |
| "app.starting", | |
| version=settings.agent_version, | |
| consolidation_interval_minutes=settings.consolidation_interval_minutes, | |
| ) | |
| # Wire scheduler start/stop into app lifespan | |
| async def start_scheduler(): | |
| scheduler.start() | |
| log.info("scheduler.started") | |
| async def stop_scheduler(): | |
| scheduler.shutdown(wait=False) | |
| log.info("scheduler.stopped") | |
| uvicorn.run( | |
| app, | |
| host="0.0.0.0", | |
| port=int(os.getenv("PORT", 8000)), | |
| log_level="info", | |
| ) | |
| if __name__ == "__main__": | |
| main() | |