"""多实例定时任务互斥。锁有过期时间,持有进程异常退出后其他实例仍能继续。""" from __future__ import annotations import os import socket from datetime import timedelta from sqlalchemy import update from sqlalchemy.exc import IntegrityError from app.clock import utcnow from app.database import session_scope from app.models import SchedulerLock OWNER = f"{socket.gethostname()}:{os.getpid()}" def acquire_lock(name: str, ttl: timedelta) -> bool: now = utcnow() until = now + ttl try: with session_scope() as session: lock = session.get(SchedulerLock, name) if lock is None: session.add(SchedulerLock(name=name, locked_until=until, owner=OWNER)) try: session.flush() except IntegrityError: session.rollback() return False return True updated = session.execute( update(SchedulerLock) .where(SchedulerLock.name == name) .where(SchedulerLock.locked_until <= now) .values(locked_until=until, owner=OWNER) ) return updated.rowcount == 1 except IntegrityError: return False