Files
MoviePilot/app/startup/subscription.py
T

101 lines
3.5 KiB
Python

"""订阅写入事务适配器的启动装配。"""
from collections.abc import Callable
from contextlib import AbstractAsyncContextManager
from datetime import datetime, timezone
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Session
from app.application.subscription.write import (
AfterCommitEffect,
AsyncAfterCommitEffect,
AsyncCreateSubscriptionCommand,
CreateSubscriptionCommand,
subscription_added_event_key,
)
from app.db.oper.subscribe import SubscribeOper
from app.db.uow import SqlAlchemyAsyncUnitOfWork, SqlAlchemyUnitOfWork
from app.startup.outbox import (
SqlAlchemyAsyncOutboxStager,
SqlAlchemyOutboxRepository,
)
class TransactionalSubscribeWriter:
"""为每次订阅新增创建独占会话,并把提交权交给 Application Command。"""
def __init__(
self,
sync_session: Callable[[], Session],
async_session: Callable[
[],
AbstractAsyncContextManager[AsyncSession],
],
) -> None:
"""注入同步会话工厂和异步会话作用域。"""
self._sync_session = sync_session
self._async_session = async_session
def add(
self,
identity: dict,
payload: dict,
username: str | None = None,
after_commit: AfterCommitEffect | None = None,
) -> tuple[int, str]:
"""在独占同步会话内执行一次完整订阅新增事务。"""
session = self._sync_session()
try:
outbox = SqlAlchemyOutboxRepository(session)
command = CreateSubscriptionCommand(
repository=SubscribeOper(session),
unit_of_work=SqlAlchemyUnitOfWork(session),
outbox=outbox,
)
def delivered(subscribe_id: int) -> None:
"""执行旧 post-commit 编排,全部成功后收口 durable intent。"""
if after_commit:
after_commit(subscribe_id)
outbox.complete_by_event_key(
subscription_added_event_key(subscribe_id, payload),
datetime.now(timezone.utc),
)
return command.execute(identity, payload, username, delivered)
finally:
session.close()
async def async_add(
self,
identity: dict,
payload: dict,
username: str | None = None,
after_commit: AsyncAfterCommitEffect | None = None,
) -> tuple[int, str]:
"""在独占异步会话作用域内执行一次完整订阅新增事务。"""
async with self._async_session() as session:
outbox = SqlAlchemyAsyncOutboxStager(session)
command = AsyncCreateSubscriptionCommand(
repository=SubscribeOper(session),
unit_of_work=SqlAlchemyAsyncUnitOfWork(session),
outbox=outbox,
)
async def delivered(subscribe_id: int) -> None:
"""异步执行旧编排,全部成功后收口 durable intent。"""
if after_commit:
await after_commit(subscribe_id)
await outbox.complete_by_event_key(
subscription_added_event_key(subscribe_id, payload),
datetime.now(timezone.utc),
)
return await command.execute(
identity,
payload,
username,
delivered,
)