internationalscholarsprogram commited on
Commit
f4df84c
·
1 Parent(s): bfa206e

fix: prevent OOM restart loop on HF Spaces

Browse files

- Reduce uvicorn workers from 2 to 1 (Playwright+Chromium is memory-heavy)
- Add --timeout-keep-alive 120 for slow PDF renders
- Make database engine lazy (no crash when MySQL unavailable)

Files changed (2) hide show
  1. Dockerfile +3 -2
  2. app/core/database.py +27 -10
Dockerfile CHANGED
@@ -53,5 +53,6 @@ COPY .env.example .env.example
53
  ENV PORT=7860
54
  EXPOSE 7860
55
 
56
- # Production command
57
- CMD ["sh", "-c", "uvicorn app.main:app --host 0.0.0.0 --port ${PORT:-7860} --workers 2"]
 
 
53
  ENV PORT=7860
54
  EXPOSE 7860
55
 
56
+ # Production command — single worker to stay within HF Spaces memory limits
57
+ # Playwright + Chromium is memory-heavy; 2 workers causes OOM restarts
58
+ CMD ["sh", "-c", "uvicorn app.main:app --host 0.0.0.0 --port ${PORT:-7860} --workers 1 --timeout-keep-alive 120"]
app/core/database.py CHANGED
@@ -1,30 +1,47 @@
1
- """Database engine and session factory (SQLAlchemy)."""
2
 
 
 
 
 
 
3
  from sqlalchemy import create_engine
4
  from sqlalchemy.orm import sessionmaker, DeclarativeBase
5
 
6
  from app.core.config import get_settings
7
 
 
 
8
 
9
  class Base(DeclarativeBase):
10
  pass
11
 
12
 
13
- _settings = get_settings()
14
 
15
- engine = create_engine(
16
- _settings.database_url,
17
- pool_pre_ping=True,
18
- pool_recycle=3600,
19
- echo=_settings.debug,
20
- )
21
 
22
- SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
 
25
  def get_db():
26
  """FastAPI dependency: yields a DB session, closes on exit."""
27
- db = SessionLocal()
 
 
28
  try:
29
  yield db
30
  finally:
 
1
+ """Database engine and session factory (SQLAlchemy).
2
 
3
+ Engine is created lazily to avoid crash on startup when no DB is available
4
+ (e.g. Hugging Face Spaces without MySQL).
5
+ """
6
+
7
+ import logging
8
  from sqlalchemy import create_engine
9
  from sqlalchemy.orm import sessionmaker, DeclarativeBase
10
 
11
  from app.core.config import get_settings
12
 
13
+ logger = logging.getLogger(__name__)
14
+
15
 
16
  class Base(DeclarativeBase):
17
  pass
18
 
19
 
20
+ _engine = None
21
 
 
 
 
 
 
 
22
 
23
+ def _get_engine():
24
+ global _engine
25
+ if _engine is None:
26
+ _settings = get_settings()
27
+ try:
28
+ _engine = create_engine(
29
+ _settings.database_url,
30
+ pool_pre_ping=True,
31
+ pool_recycle=3600,
32
+ echo=_settings.debug,
33
+ )
34
+ except Exception as exc:
35
+ logger.warning("Database engine creation failed: %s", exc)
36
+ raise
37
+ return _engine
38
 
39
 
40
  def get_db():
41
  """FastAPI dependency: yields a DB session, closes on exit."""
42
+ engine = _get_engine()
43
+ Session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
44
+ db = Session()
45
  try:
46
  yield db
47
  finally: