Files
非法操作andautofix-ci[bot] ce26b22970 refactor(api): isolate trigger execution lifecycle (#45950)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-11-10 08:17:39 +00:00

253 lines
12 KiB
Python

"""Compose trigger subscription, webhook, schedule and execution use cases."""
from collections.abc import Callable
from dataclasses import dataclass
from datetime import UTC, datetime
from functools import partial
from sqlalchemy.orm import Session, sessionmaker
from configs import dify_config
from core.app.file_access import DatabaseFileAccessController
from core.plugin.impl.oauth import OAuthHandler
from core.tools.tool_file_manager import ToolFileManager
from core.trigger.trigger_manager import TriggerManager
from core.trigger.utils.encryption import delete_cache_for_subscription
from enums import QuotaType
from extensions.ext_redis import RedisClientWrapper
from extensions.ext_storage import storage
from repositories.credentials.query_repository import CredentialQueryRepository
from repositories.sqlalchemy_workflow_trigger_log_repository import (
SQLAlchemyWorkflowTriggerExecutionRepository,
)
from repositories.trigger.app_repository import SQLAlchemyAppTriggerRepository
from repositories.trigger.debug_repository import RedisTriggerDebugRepository
from repositories.trigger.oauth_client_repository import TriggerOAuthClientRepository
from repositories.trigger.schedule_repository import TriggerScheduleRepository
from repositories.trigger.subscription_builder_repository import RedisTriggerSubscriptionBuilderRepository
from repositories.trigger.subscription_repository import (
RedisTriggerSubscriptionLocks,
RedisTriggerSubscriptionRefreshReservations,
TriggerSubscriptionRepository,
)
from services.async_workflow_service import AsyncWorkflowService, TriggerWorkflowQuery
from services.quota_service import QuotaService
from services.trigger.debug_service import TriggerDebugService
from services.trigger.debug_store import TriggerDebugEventStore
from services.trigger.endpoint_gateway import PluginTriggerEndpointGateway, enqueue_triggered_workflows
from services.trigger.endpoint_service import TriggerEndpointService
from services.trigger.event_gateway import PluginTriggerEventGateway
from services.trigger.event_service import TriggerEventService
from services.trigger.execution_gateway import WorkflowTriggerExecutionGateway
from services.trigger.execution_service import TriggerExecutionService
from services.trigger.execution_store import TriggerExecutionStore
from services.trigger.oauth_client_service import TriggerOAuthClientService
from services.trigger.oauth_gateway import (
OAuthProxyContextGateway,
PluginTriggerOAuthGateway,
TriggerOAuthBuilderGateway,
)
from services.trigger.oauth_service import TriggerOAuthService
from services.trigger.provider_gateway import PluginTriggerProviderQuery
from services.trigger.provider_query import TriggerProviderQuery
from services.trigger.schedule_gateway import ScheduleWorkflowGateway, publish_schedules
from services.trigger.schedule_service import SchedulePublicationService, TriggerScheduleService
from services.trigger.subscription_binding_service import (
TriggerSubscriptionBindingQuery,
TriggerSubscriptionBindingService,
)
from services.trigger.subscription_codec import ProviderTriggerSubscriptionCodec
from services.trigger.subscription_gateway import (
PluginTriggerSubscriptionGateway,
enqueue_subscription_refresh,
invalidate_subscription_properties,
)
from services.trigger.subscription_query_service import TriggerSubscriptionQueryService
from services.trigger.subscription_refresh_service import TriggerSubscriptionRefreshService
from services.trigger.subscription_renewal_service import TriggerSubscriptionRenewalService
from services.trigger.subscription_service import TriggerSubscriptionService
from services.trigger.trigger_request_service import TriggerHttpRequestCachingService
from services.trigger.trigger_subscription_builder_service import TriggerSubscriptionBuilderService
from services.trigger.webhook_gateway import ToolWebhookFiles
from services.trigger.webhook_service import (
WebhookBindingService,
WebhookFiles,
WebhookService,
)
from services.trigger.workflow_dispatch_service import PluginTriggerWorkflowDispatchService, TriggerEndUserProvisioner
from services.workflow.queue_dispatcher import CeleryWorkflowQueuePublisher
@dataclass(frozen=True, slots=True)
class TriggerServices:
providers: TriggerProviderQuery
subscriptions: TriggerSubscriptionQueryService
binding_queries: TriggerSubscriptionBindingQuery
create_binding_service: Callable[[Session], TriggerSubscriptionBindingService]
subscription_management: TriggerSubscriptionService
subscription_renewal: TriggerSubscriptionRenewalService
subscription_refresh: TriggerSubscriptionRefreshService
builders: TriggerSubscriptionBuilderService
endpoints: TriggerEndpointService
events: TriggerEventService
debug: TriggerDebugService
debug_events: TriggerDebugEventStore
workflow_dispatch: AsyncWorkflowService
executions: TriggerExecutionService
execution_logs: TriggerExecutionStore
webhooks: WebhookService
webhook_files: WebhookFiles
webhook_draft_bindings: WebhookBindingService
create_webhook_publication_service: Callable[[Session], WebhookBindingService]
plugin_workflow_dispatch: PluginTriggerWorkflowDispatchService
schedules: TriggerScheduleService
create_schedule_publication_service: Callable[[Session], SchedulePublicationService]
oauth_clients: TriggerOAuthClientService
oauth: TriggerOAuthService
def build_trigger_services(
*,
database_client: sessionmaker[Session],
redis: RedisClientWrapper,
credentials: CredentialQueryRepository,
subscriptions: TriggerSubscriptionRepository,
workflow_queries: TriggerWorkflowQuery,
trigger_end_users: TriggerEndUserProvisioner,
mark_rate_limited: Callable[[str], None],
) -> TriggerServices:
trigger_providers = PluginTriggerProviderQuery()
subscription_provider = PluginTriggerSubscriptionGateway()
subscription_locks = RedisTriggerSubscriptionLocks(redis=redis)
subscription_codec = ProviderTriggerSubscriptionCodec()
trigger_subscription_management = TriggerSubscriptionService(
subscriptions=subscriptions,
providers=subscription_provider,
locks=subscription_locks,
codec=subscription_codec,
invalidate_cache=delete_cache_for_subscription,
)
trigger_builders = TriggerSubscriptionBuilderService(
builders=RedisTriggerSubscriptionBuilderRepository(redis=redis),
get_provider=TriggerManager.get_trigger_provider,
subscribe=TriggerManager.subscribe_trigger,
create_subscription=trigger_subscription_management.create,
)
trigger_oauth_provider = PluginTriggerOAuthGateway(oauth=OAuthHandler())
trigger_oauth_clients = TriggerOAuthClientService(
clients=TriggerOAuthClientRepository(session_factory=database_client),
providers=trigger_oauth_provider,
)
trigger_subscriptions = TriggerSubscriptionQueryService(
credentials=credentials, schemas=trigger_providers, subscriptions=subscriptions
)
renewal = TriggerSubscriptionRenewalService(
subscriptions=subscriptions,
providers=subscription_provider,
oauth=trigger_oauth_provider,
clients=trigger_oauth_clients,
locks=subscription_locks,
codec=subscription_codec,
credential_threshold=dify_config.TRIGGER_PROVIDER_CREDENTIAL_THRESHOLD_SECONDS,
subscription_threshold=dify_config.TRIGGER_PROVIDER_SUBSCRIPTION_THRESHOLD_SECONDS,
console_api_url=dify_config.CONSOLE_API_URL,
invalidate_cache=delete_cache_for_subscription,
invalidate_properties=invalidate_subscription_properties,
)
trigger_requests = TriggerHttpRequestCachingService(storage=storage)
trigger_debug_events = RedisTriggerDebugRepository(redis=redis)
trigger_events = TriggerEventService(
subscriptions=trigger_subscriptions,
plugins=PluginTriggerEventGateway(),
requests=trigger_requests,
)
execution_logs = SQLAlchemyWorkflowTriggerExecutionRepository(session_factory=database_client)
execution_runtime = WorkflowTriggerExecutionGateway(
models=execution_logs, logs=execution_logs, session_factory=database_client
)
queues = CeleryWorkflowQueuePublisher()
workflow_dispatch = AsyncWorkflowService(
workflows=workflow_queries, logs=execution_logs, queues=queues, reserve_quota=QuotaService.reserve
)
app_triggers = SQLAlchemyAppTriggerRepository(session_factory=database_client)
schedules = TriggerScheduleRepository(session_factory=database_client)
return TriggerServices(
providers=trigger_providers,
subscriptions=trigger_subscriptions,
binding_queries=subscriptions,
# Bind only for the duration of the caller's publication transaction.
create_binding_service=lambda session: TriggerSubscriptionBindingService(
sync_bindings=partial(subscriptions.sync_workflow_bindings, session=session)
),
events=trigger_events,
debug_events=trigger_debug_events,
debug=TriggerDebugService(
events=trigger_debug_events,
schedules=trigger_debug_events,
invoke_plugin_event=trigger_events.invoke_debug,
now=lambda: datetime.now(UTC),
),
workflow_dispatch=workflow_dispatch,
executions=TriggerExecutionService(logs=execution_logs, run=execution_runtime.run),
execution_logs=execution_logs,
webhooks=WebhookService(
webhooks=app_triggers,
end_users=trigger_end_users,
dispatch=workflow_dispatch,
reserve_quota=QuotaService.reserve,
mark_rate_limited=mark_rate_limited,
),
webhook_files=ToolWebhookFiles(manager=ToolFileManager(), access=DatabaseFileAccessController()),
webhook_draft_bindings=WebhookBindingService(sync_bindings=app_triggers.sync_draft_webhooks),
# Publish binding changes atomically with the workflow that owns them.
create_webhook_publication_service=lambda session: WebhookBindingService(
sync_bindings=partial(app_triggers.sync_webhooks, session=session, remove_stale=True)
),
plugin_workflow_dispatch=PluginTriggerWorkflowDispatchService(
workflows=workflow_queries,
logs=execution_logs,
queues=queues,
dispatch=workflow_dispatch,
events=trigger_events,
bindings=subscriptions,
end_users=trigger_end_users,
reserve_quota=QuotaService.reserve,
mark_rate_limited=mark_rate_limited,
),
schedules=TriggerScheduleService(
schedules=schedules,
publish=publish_schedules,
dispatch=ScheduleWorkflowGateway(workflows=workflow_dispatch),
reserve=partial(QuotaService.reserve, QuotaType.TRIGGER),
mark_rate_limited=mark_rate_limited,
now=lambda: datetime.now(UTC),
batch_size=dify_config.WORKFLOW_SCHEDULE_POLLER_BATCH_SIZE,
max_dispatch_per_tick=dify_config.WORKFLOW_SCHEDULE_MAX_DISPATCH_PER_TICK,
),
create_schedule_publication_service=lambda session: SchedulePublicationService(
sync_schedule=partial(schedules.sync_publication, session=session), now=lambda: datetime.now(UTC)
),
subscription_management=trigger_subscription_management,
subscription_renewal=renewal,
subscription_refresh=TriggerSubscriptionRefreshService(
subscriptions=subscriptions,
reservations=RedisTriggerSubscriptionRefreshReservations(redis=redis),
publish=enqueue_subscription_refresh,
renewal=renewal,
),
builders=trigger_builders,
endpoints=TriggerEndpointService(
subscriptions=subscriptions,
provider=PluginTriggerEndpointGateway(),
requests=trigger_requests,
publish=enqueue_triggered_workflows,
),
oauth_clients=trigger_oauth_clients,
oauth=TriggerOAuthService(
clients=trigger_oauth_clients,
providers=trigger_oauth_provider,
contexts=OAuthProxyContextGateway(),
builders=TriggerOAuthBuilderGateway(builders=trigger_builders),
),
)