每次任务执行时用 _make_session() 创建独立的 engine + session,用完 eng.dispose() 释放,彻底避免 loop 冲突。
This commit is contained in:
@@ -26,7 +26,7 @@ from sqlalchemy import select
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../../.."))
|
||||
|
||||
from shared.models.base import AsyncSessionLocal
|
||||
from shared.models.base import Base
|
||||
from shared.models.task import Task
|
||||
from shared.models.account import Account
|
||||
from shared.models.signin_log import SigninLog
|
||||
@@ -38,6 +38,23 @@ from ..config import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _make_session():
|
||||
"""
|
||||
每次创建新的 engine + session,避免 Celery worker fork 后
|
||||
复用主进程 event loop 绑定的连接池导致 'Future attached to a different loop' 错误。
|
||||
"""
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
|
||||
engine_kwargs: dict = {"echo": False}
|
||||
if "sqlite" not in shared_settings.DATABASE_URL:
|
||||
engine_kwargs.update(pool_size=5, max_overflow=10, pool_pre_ping=True)
|
||||
|
||||
eng = create_async_engine(shared_settings.DATABASE_URL, **engine_kwargs)
|
||||
factory = sessionmaker(eng, class_=AsyncSession, expire_on_commit=False)
|
||||
return factory, eng
|
||||
|
||||
WEIBO_HEADERS = {
|
||||
"User-Agent": (
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
|
||||
@@ -117,7 +134,9 @@ async def _async_check_due():
|
||||
now = datetime.now()
|
||||
submitted = 0
|
||||
|
||||
async with AsyncSessionLocal() as session:
|
||||
SessionFactory, eng = _make_session()
|
||||
try:
|
||||
async with SessionFactory() as session:
|
||||
stmt = (
|
||||
select(Task, Account)
|
||||
.join(Account, Task.account_id == Account.id)
|
||||
@@ -126,6 +145,8 @@ async def _async_check_due():
|
||||
)
|
||||
result = await session.execute(stmt)
|
||||
pairs = result.all()
|
||||
finally:
|
||||
await eng.dispose()
|
||||
|
||||
for task, account in pairs:
|
||||
try:
|
||||
@@ -212,7 +233,9 @@ async def _async_do_signin(account_id: str) -> Dict[str, Any]:
|
||||
"""直接操作数据库和微博 API 完成签到"""
|
||||
import httpx
|
||||
|
||||
async with AsyncSessionLocal() as session:
|
||||
SessionFactory, eng = _make_session()
|
||||
try:
|
||||
async with SessionFactory() as session:
|
||||
stmt = select(Account).where(Account.id == account_id)
|
||||
result = await session.execute(stmt)
|
||||
account = result.scalar_one_or_none()
|
||||
@@ -279,6 +302,8 @@ async def _async_do_signin(account_id: str) -> Dict[str, Any]:
|
||||
"failed": failed,
|
||||
"total_topics": len(topics),
|
||||
}
|
||||
finally:
|
||||
await eng.dispose()
|
||||
|
||||
|
||||
async def _fetch_topics(cookies: Dict[str, str]) -> List[dict]:
|
||||
|
||||
Reference in New Issue
Block a user