mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-29 03:56:43 +08:00
refactor: make subscription lifecycle events durable
This commit is contained in:
+63
-1
@@ -6,7 +6,18 @@ from typing import cast
|
||||
from fastapi import Depends, Request
|
||||
|
||||
from app.application.messaging.chat import AsyncAgentChatRepository, AsyncUnitOfWork
|
||||
from app.startup.context import AgentChatRuntime, HostRuntime
|
||||
from app.application.outbox import AsyncOutboxTransaction
|
||||
from app.application.subscription.delete import SubscribeDeletionRepository
|
||||
from app.application.subscription.identity import SubscribeIdentityDeletionRepository
|
||||
from app.application.subscription.mutation import (
|
||||
SubscriptionHistoryMutationRepository,
|
||||
SubscriptionMutationRepository,
|
||||
)
|
||||
from app.startup.context import (
|
||||
AgentChatRuntime,
|
||||
HostRuntime,
|
||||
SubscriptionRuntime,
|
||||
)
|
||||
|
||||
|
||||
def get_host_runtime(request: Request) -> HostRuntime:
|
||||
@@ -46,3 +57,54 @@ def get_agent_chat_transaction(
|
||||
) -> AsyncUnitOfWork:
|
||||
"""构造绑定当前请求会话的 Agent 会话事务端口。"""
|
||||
return cast(AsyncUnitOfWork, runtime.transaction(session))
|
||||
|
||||
|
||||
def get_subscription_runtime(
|
||||
runtime: HostRuntime = Depends(get_host_runtime),
|
||||
) -> SubscriptionRuntime:
|
||||
"""从完整宿主运行时收窄到订阅写事务能力。"""
|
||||
return runtime.subscription
|
||||
|
||||
|
||||
async def get_subscription_session(
|
||||
runtime: SubscriptionRuntime = Depends(get_subscription_runtime),
|
||||
) -> AsyncGenerator[object, None]:
|
||||
"""从订阅运行时生成请求独占的异步会话。"""
|
||||
async for session in runtime.async_session():
|
||||
yield session
|
||||
|
||||
|
||||
def get_subscription_repository(
|
||||
session: object = Depends(get_subscription_session),
|
||||
runtime: SubscriptionRuntime = Depends(get_subscription_runtime),
|
||||
) -> (
|
||||
SubscriptionMutationRepository
|
||||
| SubscribeDeletionRepository
|
||||
| SubscribeIdentityDeletionRepository
|
||||
):
|
||||
"""构造绑定当前请求会话的订阅仓储。"""
|
||||
return runtime.repository(session)
|
||||
|
||||
|
||||
def get_subscription_history_repository(
|
||||
session: object = Depends(get_subscription_session),
|
||||
runtime: SubscriptionRuntime = Depends(get_subscription_runtime),
|
||||
) -> SubscriptionHistoryMutationRepository:
|
||||
"""构造绑定当前请求会话的订阅历史仓储。"""
|
||||
return runtime.history_repository(session)
|
||||
|
||||
|
||||
def get_subscription_transaction(
|
||||
session: object = Depends(get_subscription_session),
|
||||
runtime: SubscriptionRuntime = Depends(get_subscription_runtime),
|
||||
) -> AsyncUnitOfWork:
|
||||
"""构造绑定当前订阅请求会话的异步事务端口。"""
|
||||
return cast(AsyncUnitOfWork, runtime.transaction(session))
|
||||
|
||||
|
||||
def get_subscription_outbox(
|
||||
session: object = Depends(get_subscription_session),
|
||||
runtime: SubscriptionRuntime = Depends(get_subscription_runtime),
|
||||
) -> AsyncOutboxTransaction:
|
||||
"""构造与订阅写入共享请求会话的 outbox 端口。"""
|
||||
return runtime.outbox(session)
|
||||
|
||||
@@ -1,17 +1,36 @@
|
||||
"""订阅领域的请求级 command/query 依赖。"""
|
||||
|
||||
from typing import Any, cast
|
||||
|
||||
from fastapi import BackgroundTasks, Depends
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.adapters.external.server import MoviePilotServerHelper
|
||||
from app.api.context import (
|
||||
get_subscription_history_repository,
|
||||
get_subscription_outbox,
|
||||
get_subscription_repository,
|
||||
get_subscription_transaction,
|
||||
)
|
||||
from app.api.data import get_async_db, get_db
|
||||
from app.api.dependencies.data import repository, transaction
|
||||
from app.api.dependencies.data import repository
|
||||
from app.application.outbox import AsyncOutboxTransaction
|
||||
from app.application.scheduling import Scheduler
|
||||
from app.application.servarr import ServarrSubscriptionService
|
||||
from app.application.subscription.delete import DeleteSubscribeCommand
|
||||
from app.application.subscription.delete import (
|
||||
AsyncUnitOfWork as DeleteUnitOfWork,
|
||||
DeleteSubscribeCommand,
|
||||
SubscribeDeletionRepository,
|
||||
)
|
||||
from app.application.subscription.identity import DeleteSubscriptionsByIdentityCommand
|
||||
from app.application.subscription.mutation import SubscriptionMutationService
|
||||
from app.application.subscription.identity import SubscribeIdentityDeletionRepository
|
||||
from app.application.subscription.mutation import (
|
||||
AsyncUnitOfWork as MutationUnitOfWork,
|
||||
SubscriptionHistoryMutationRepository,
|
||||
SubscriptionMutationRepository,
|
||||
SubscriptionMutationService,
|
||||
)
|
||||
from app.application.subscription.query import SubscriptionQueryService
|
||||
from app.application.subscription.search import SearchSubscriptionsCommand
|
||||
from app.runtime.events import eventmanager
|
||||
@@ -20,25 +39,29 @@ from app.schemas.types import EventType
|
||||
|
||||
|
||||
async def _publish_subscribe_deleted(
|
||||
subscribe_id: int,
|
||||
subscribe_info: dict,
|
||||
payload: dict[str, Any],
|
||||
) -> None:
|
||||
"""通过宿主事件总线发布已提交的订阅删除事件。"""
|
||||
await eventmanager.async_send_event(
|
||||
EventType.SubscribeDeleted,
|
||||
{"subscribe_id": subscribe_id, "subscribe_info": subscribe_info},
|
||||
)
|
||||
await eventmanager.async_send_event(EventType.SubscribeDeleted, payload)
|
||||
|
||||
|
||||
async def _publish_subscribe_modified(payload: dict[str, Any]) -> None:
|
||||
"""通过宿主事件总线发布已提交的订阅修改事件。"""
|
||||
await eventmanager.async_send_event(EventType.SubscribeModified, payload)
|
||||
|
||||
|
||||
def get_delete_subscribe_command(
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
repository_port: object = Depends(get_subscription_repository),
|
||||
unit_of_work: object = Depends(get_subscription_transaction),
|
||||
outbox: AsyncOutboxTransaction = Depends(get_subscription_outbox),
|
||||
) -> DeleteSubscribeCommand:
|
||||
"""组装请求级订阅删除用例及其具体适配器。"""
|
||||
return DeleteSubscribeCommand(
|
||||
repository=repository("subscribe", db),
|
||||
unit_of_work=transaction("async", db),
|
||||
repository=cast(SubscribeDeletionRepository, repository_port),
|
||||
unit_of_work=cast(DeleteUnitOfWork, unit_of_work),
|
||||
publish_deleted=_publish_subscribe_deleted,
|
||||
report_deleted=MoviePilotServerHelper.sub_done_async,
|
||||
outbox=outbox,
|
||||
)
|
||||
|
||||
|
||||
@@ -54,14 +77,17 @@ def _log_subscribe_deleted_event_error(
|
||||
|
||||
|
||||
def get_delete_subscriptions_by_identity_command(
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
repository_port: object = Depends(get_subscription_repository),
|
||||
unit_of_work: object = Depends(get_subscription_transaction),
|
||||
outbox: AsyncOutboxTransaction = Depends(get_subscription_outbox),
|
||||
) -> DeleteSubscriptionsByIdentityCommand:
|
||||
"""组装请求级按媒体身份删除订阅用例。"""
|
||||
return DeleteSubscriptionsByIdentityCommand(
|
||||
repository=repository("subscribe", db),
|
||||
unit_of_work=transaction("async", db),
|
||||
repository=cast(SubscribeIdentityDeletionRepository, repository_port),
|
||||
unit_of_work=cast(DeleteUnitOfWork, unit_of_work),
|
||||
publish_deleted=_publish_subscribe_deleted,
|
||||
handle_event_error=_log_subscribe_deleted_event_error,
|
||||
outbox=outbox,
|
||||
)
|
||||
|
||||
|
||||
@@ -98,12 +124,20 @@ def get_subscription_query_service(
|
||||
|
||||
|
||||
def get_subscription_mutation_service(
|
||||
db: AsyncSession = Depends(get_async_db),
|
||||
repository_port: object = Depends(get_subscription_repository),
|
||||
history_repository: SubscriptionHistoryMutationRepository = Depends(
|
||||
get_subscription_history_repository
|
||||
),
|
||||
unit_of_work: object = Depends(get_subscription_transaction),
|
||||
outbox: AsyncOutboxTransaction = Depends(get_subscription_outbox),
|
||||
) -> SubscriptionMutationService:
|
||||
"""组装异步订阅写服务。"""
|
||||
return SubscriptionMutationService(
|
||||
repository=repository("subscribe", db),
|
||||
history_repository=repository("subscribe_history", db),
|
||||
repository=cast(SubscriptionMutationRepository, repository_port),
|
||||
history_repository=history_repository,
|
||||
unit_of_work=cast(MutationUnitOfWork, unit_of_work),
|
||||
outbox=outbox,
|
||||
publish_modified=_publish_subscribe_modified,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ from app.schemas.workflow import Subscribe as _SchemaSubscribe
|
||||
from app.api.response import ResponseAPIRouter
|
||||
from app.chain.subscribe import SubscribeChain
|
||||
from app.runtime.config import settings
|
||||
from app.domain.context import MediaInfo
|
||||
from app.runtime.events import eventmanager
|
||||
from app.domain.context import MediaInfo
|
||||
from app.domain.metainfo import MetaInfo
|
||||
from app.adapters.web.security.access import verify_token, verify_apitoken
|
||||
from app.application.subscription.delete import (
|
||||
@@ -294,16 +294,16 @@ async def update_subscribe(
|
||||
)
|
||||
if not change:
|
||||
return _SchemaResponse(success=False, message="订阅不存在")
|
||||
# 发送订阅调整事件
|
||||
await eventmanager.async_send_event(
|
||||
EventType.SubscribeModified,
|
||||
SubscribeModifiedEventData(
|
||||
subscribe_id=subscribe_in.id,
|
||||
old_subscribe_info=change.old,
|
||||
subscribe_info=change.new,
|
||||
scene="update",
|
||||
).to_dict(),
|
||||
)
|
||||
if not change.event_published:
|
||||
await eventmanager.async_send_event(
|
||||
EventType.SubscribeModified,
|
||||
SubscribeModifiedEventData(
|
||||
subscribe_id=subscribe_in.id,
|
||||
old_subscribe_info=change.old,
|
||||
subscribe_info=change.new,
|
||||
scene="update",
|
||||
).to_dict(),
|
||||
)
|
||||
return _SchemaResponse(success=True)
|
||||
|
||||
|
||||
@@ -327,16 +327,16 @@ async def update_subscribe_status(
|
||||
change = await mutation.update_status(subid, state, actor)
|
||||
if not change:
|
||||
return _SchemaResponse(success=False, message="订阅不存在")
|
||||
# 发送订阅调整事件
|
||||
await eventmanager.async_send_event(
|
||||
EventType.SubscribeModified,
|
||||
SubscribeModifiedEventData(
|
||||
subscribe_id=subid,
|
||||
old_subscribe_info=change.old,
|
||||
subscribe_info=change.new,
|
||||
scene="status",
|
||||
).to_dict(),
|
||||
)
|
||||
if not change.event_published:
|
||||
await eventmanager.async_send_event(
|
||||
EventType.SubscribeModified,
|
||||
SubscribeModifiedEventData(
|
||||
subscribe_id=subid,
|
||||
old_subscribe_info=change.old,
|
||||
subscribe_info=change.new,
|
||||
scene="status",
|
||||
).to_dict(),
|
||||
)
|
||||
return _SchemaResponse(success=True)
|
||||
|
||||
|
||||
@@ -388,15 +388,16 @@ async def reset_subscribes(
|
||||
)
|
||||
change = await mutation.reset(subid, actor)
|
||||
if change:
|
||||
await eventmanager.async_send_event(
|
||||
EventType.SubscribeModified,
|
||||
SubscribeModifiedEventData(
|
||||
subscribe_id=subid,
|
||||
old_subscribe_info=change.old,
|
||||
subscribe_info=change.new,
|
||||
scene="reset",
|
||||
).to_dict(),
|
||||
)
|
||||
if not change.event_published:
|
||||
await eventmanager.async_send_event(
|
||||
EventType.SubscribeModified,
|
||||
SubscribeModifiedEventData(
|
||||
subscribe_id=subid,
|
||||
old_subscribe_info=change.old,
|
||||
subscribe_info=change.new,
|
||||
scene="reset",
|
||||
).to_dict(),
|
||||
)
|
||||
return _SchemaResponse(success=True)
|
||||
return _SchemaResponse(success=False, message="订阅不存在")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user