From a3cf73b220e526c70bf9f59c3c35617e39236562 Mon Sep 17 00:00:00 2001 From: Yeuoly Date: Thu, 22 Jan 2026 19:54:54 +0800 Subject: [PATCH] feat: refactor initializers to support async and sync execution --- api/core/sandbox/builder.py | 11 ++++------- api/core/sandbox/initializer/__init__.py | 4 +++- .../sandbox/initializer/app_assets_attrs_loader.py | 8 ++++---- .../sandbox/initializer/app_assets_initializer.py | 11 ++++------- api/core/sandbox/initializer/base.py | 14 ++++++++------ .../sandbox/initializer/dify_cli_initializer.py | 7 ++----- .../initializer/draft_app_assets_initializer.py | 11 ++++------- api/core/sandbox/initializer/skill_initializer.py | 4 ++-- 8 files changed, 31 insertions(+), 39 deletions(-) diff --git a/api/core/sandbox/builder.py b/api/core/sandbox/builder.py index 9edf54005b..772f1d3ddc 100644 --- a/api/core/sandbox/builder.py +++ b/api/core/sandbox/builder.py @@ -9,7 +9,7 @@ from core.entities.provider_entities import BasicProviderConfig from core.virtual_environment.__base.virtual_environment import VirtualEnvironment from .entities.sandbox_type import SandboxType -from .initializer import SandboxInitializer +from .initializer import AsyncSandboxInitializer, SandboxInitializer, SyncSandboxInitializer from .sandbox import Sandbox if TYPE_CHECKING: @@ -113,19 +113,16 @@ class SandboxBuilder: assets_id=self._assets_id, ) - """ # Run synchronous initializers before marking sandbox as ready. - """ for init in self._initializers: - if init.async_initialize(): - continue - init.initialize(sandbox) + if isinstance(init, SyncSandboxInitializer): + init.initialize(sandbox) # Run sandbox setup asynchronously so workflow execution can proceed. def initialize() -> None: try: for init in self._initializers: - if not init.async_initialize(): + if not isinstance(init, AsyncSandboxInitializer): continue if sandbox.is_cancelled(): diff --git a/api/core/sandbox/initializer/__init__.py b/api/core/sandbox/initializer/__init__.py index 8e0cd14b3e..eca2b15a66 100644 --- a/api/core/sandbox/initializer/__init__.py +++ b/api/core/sandbox/initializer/__init__.py @@ -1,11 +1,13 @@ from .app_assets_initializer import AppAssetsInitializer -from .base import SandboxInitializer +from .base import AsyncSandboxInitializer, SandboxInitializer, SyncSandboxInitializer from .dify_cli_initializer import DifyCliInitializer from .draft_app_assets_initializer import DraftAppAssetsInitializer __all__ = [ "AppAssetsInitializer", + "AsyncSandboxInitializer", "DifyCliInitializer", "DraftAppAssetsInitializer", "SandboxInitializer", + "SyncSandboxInitializer", ] diff --git a/api/core/sandbox/initializer/app_assets_attrs_loader.py b/api/core/sandbox/initializer/app_assets_attrs_loader.py index 32efd41254..f3c19eaad2 100644 --- a/api/core/sandbox/initializer/app_assets_attrs_loader.py +++ b/api/core/sandbox/initializer/app_assets_attrs_loader.py @@ -1,16 +1,16 @@ from core.app_assets.constants import AppAssetsAttrs -from core.sandbox.initializer.base import SandboxInitializer +from core.sandbox.initializer.base import SyncSandboxInitializer from core.sandbox.sandbox import Sandbox from services.app_asset_service import AppAssetService -class AppAssetsAttrsInitializer(SandboxInitializer): +class AppAssetsAttrsInitializer(SyncSandboxInitializer): def __init__(self, tenant_id: str, app_id: str, assets_id: str) -> None: self._tenant_id = tenant_id self._app_id = app_id self._assets_id = assets_id - def initialize(self, env: Sandbox) -> None: + def initialize(self, sandbox: Sandbox) -> None: # Load published app assets and unzip the artifact bundle. app_assets = AppAssetService.get_tenant_app_assets(self._tenant_id, self._assets_id) - env.attrs.set(AppAssetsAttrs.FILE_TREE, app_assets.asset_tree) + sandbox.attrs.set(AppAssetsAttrs.FILE_TREE, app_assets.asset_tree) diff --git a/api/core/sandbox/initializer/app_assets_initializer.py b/api/core/sandbox/initializer/app_assets_initializer.py index e0a94a41e9..ba21739014 100644 --- a/api/core/sandbox/initializer/app_assets_initializer.py +++ b/api/core/sandbox/initializer/app_assets_initializer.py @@ -7,21 +7,21 @@ from extensions.ext_storage import storage from extensions.storage.file_presign_storage import FilePresignStorage from ..entities import AppAssets -from .base import SandboxInitializer +from .base import AsyncSandboxInitializer logger = logging.getLogger(__name__) APP_ASSETS_DOWNLOAD_TIMEOUT = 60 * 10 -class AppAssetsInitializer(SandboxInitializer): +class AppAssetsInitializer(AsyncSandboxInitializer): def __init__(self, tenant_id: str, app_id: str, assets_id: str) -> None: self._tenant_id = tenant_id self._app_id = app_id self._assets_id = assets_id - def initialize(self, env: Sandbox) -> None: - vm = env.vm + def initialize(self, sandbox: Sandbox) -> None: + vm = sandbox.vm zip_key = AssetPaths.build_zip(self._tenant_id, self._app_id, self._assets_id) download_url = FilePresignStorage(storage.storage_runner).get_download_url(zip_key) @@ -45,6 +45,3 @@ class AppAssetsInitializer(SandboxInitializer): self._app_id, self._assets_id, ) - - def async_initialize(self) -> bool: - return True diff --git a/api/core/sandbox/initializer/base.py b/api/core/sandbox/initializer/base.py index ba358e7371..93bd27b9b7 100644 --- a/api/core/sandbox/initializer/base.py +++ b/api/core/sandbox/initializer/base.py @@ -5,10 +5,12 @@ from core.sandbox.sandbox import Sandbox class SandboxInitializer(ABC): @abstractmethod - def initialize(self, env: Sandbox) -> None: ... + def initialize(self, sandbox: Sandbox) -> None: ... - def async_initialize(self) -> bool: - """ - Whether the initializer needs to run asynchronously. - """ - return False + +class SyncSandboxInitializer(SandboxInitializer): + """Marker class for initializers that must run before async setup.""" + + +class AsyncSandboxInitializer(SandboxInitializer): + """Marker class for initializers that can run in the background.""" diff --git a/api/core/sandbox/initializer/dify_cli_initializer.py b/api/core/sandbox/initializer/dify_cli_initializer.py index cde75be3d1..816260a264 100644 --- a/api/core/sandbox/initializer/dify_cli_initializer.py +++ b/api/core/sandbox/initializer/dify_cli_initializer.py @@ -12,12 +12,12 @@ from core.virtual_environment.__base.helpers import pipeline from ..bash.dify_cli import DifyCliConfig, DifyCliLocator from ..entities import DifyCli -from .base import SandboxInitializer +from .base import AsyncSandboxInitializer logger = logging.getLogger(__name__) -class DifyCliInitializer(SandboxInitializer): +class DifyCliInitializer(AsyncSandboxInitializer): def __init__( self, tenant_id: str, @@ -82,6 +82,3 @@ class DifyCliInitializer(SandboxInitializer): ).execute(raise_on_error=True) logger.info("Global tools initialized, path=%s, tool_count=%d", DifyCli.GLOBAL_TOOLS_PATH, len(self._tools)) - - def async_initialize(self) -> bool: - return True diff --git a/api/core/sandbox/initializer/draft_app_assets_initializer.py b/api/core/sandbox/initializer/draft_app_assets_initializer.py index 18b022b028..13464cfaf5 100644 --- a/api/core/sandbox/initializer/draft_app_assets_initializer.py +++ b/api/core/sandbox/initializer/draft_app_assets_initializer.py @@ -7,21 +7,21 @@ from core.sandbox.services.asset_download_service import AssetDownloadItem from core.virtual_environment.__base.helpers import pipeline from services.app_asset_service import AppAssetService -from .base import SandboxInitializer +from .base import AsyncSandboxInitializer logger = logging.getLogger(__name__) DRAFT_ASSETS_DOWNLOAD_TIMEOUT = 60 * 10 -class DraftAppAssetsInitializer(SandboxInitializer): +class DraftAppAssetsInitializer(AsyncSandboxInitializer): def __init__(self, tenant_id: str, app_id: str, assets_id: str) -> None: self._tenant_id = tenant_id self._app_id = app_id self._assets_id = assets_id - def initialize(self, env: Sandbox) -> None: - vm = env.vm + def initialize(self, sandbox: Sandbox) -> None: + vm = sandbox.vm # Draft assets download via presigned URLs to avoid zip build overhead. # FIXME(Yeuoly): merge 2 IO operations in DraftAppAssetsInitializer and AppAssetsAttrsInitializer app_assets = AppAssetService.get_tenant_app_assets(self._tenant_id, self._assets_id) @@ -41,6 +41,3 @@ class DraftAppAssetsInitializer(SandboxInitializer): self._app_id, self._assets_id, ) - - def async_initialize(self) -> bool: - return True diff --git a/api/core/sandbox/initializer/skill_initializer.py b/api/core/sandbox/initializer/skill_initializer.py index 5a0b0adf81..2f87fbf22f 100644 --- a/api/core/sandbox/initializer/skill_initializer.py +++ b/api/core/sandbox/initializer/skill_initializer.py @@ -6,12 +6,12 @@ from core.sandbox.sandbox import Sandbox from core.skill import SkillAttrs from core.skill.skill_manager import SkillManager -from .base import SandboxInitializer +from .base import SyncSandboxInitializer logger = logging.getLogger(__name__) -class SkillInitializer(SandboxInitializer): +class SkillInitializer(SyncSandboxInitializer): def __init__( self, tenant_id: str,